<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://sofsog.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://sofsog.com/" rel="alternate" type="text/html" /><updated>2026-09-12T09:32:33+00:00</updated><id>https://sofsog.com/feed.xml</id><title type="html">Blog của Thành</title><subtitle>Đây là trang blog cá nhân của Thành, vừa là nơi chia sẻ, vừa là nơi ghi chú lại những kinh nghiệm cá nhân.</subtitle><author><name>Thành</name></author><entry><title type="html">Kéo 154 repo GitHub về NAS: mirror tự cập nhật bằng Gitea</title><link href="https://sofsog.com/server/keo-154-repo-github-ve-nas-bang-gitea" rel="alternate" type="text/html" title="Kéo 154 repo GitHub về NAS: mirror tự cập nhật bằng Gitea" /><published>2026-09-12T00:00:00+00:00</published><updated>2026-09-12T00:00:00+00:00</updated><id>https://sofsog.com/server/keo-154-repo-github-ve-nas-bang-gitea</id><content type="html" xml:base="https://sofsog.com/server/keo-154-repo-github-ve-nas-bang-gitea"><![CDATA[<p>Mình có 154 repo trên GitHub, tất cả nằm dưới một tài khoản duy nhất. Mất tài khoản đó là mất sạch.</p>

<p>Không cần tới chuyện bị khoá tài khoản mới thành vấn đề — đổi chính sách, mất khoá xác thực hai lớp, hay đơn giản là một hôm nào đó không đăng nhập được, hậu quả đều giống nhau.</p>

<aside class="series-box" aria-label="Các bài trong series Tự dựng server tại nhà"><p class="series-box__dau">Series <a href="/series/">Tự dựng server tại nhà</a> &middot; bài 9/9 <span class="series-box__cap">Nâng cao</span></p><ol class="series-box__ds"><li><a href="/server/dung-gitea-tren-nas-dong-bo-obsidian-giua-pc-va-dien-thoai">Dựng Gitea trên NAS - "GitHub riêng" để đồng bộ Obsidian giữa PC và điện thoại</a></li><li><a href="/server/tailscale-vao-nas-tu-xa-khong-mo-port">Tailscale - vào NAS từ bất cứ đâu mà không mở port trên router</a></li><li><a href="/server/vaultwarden-tren-nas-kho-mat-khau-cho-ca-nha">Vaultwarden trên NAS - kho mật khẩu cho cả nhà, không trả phí hằng tháng</a></li><li><a href="/server/chon-nas-dau-tien-mua-dung-san-hay-tu-lap">Chọn NAS đầu tiên - mua hộp dựng sẵn hay tự lắp từ máy chủ cũ</a></li><li><a href="/server/quy-tac-3-2-1-lam-cho-that">Quy tắc 3-2-1 làm cho thật - ngồi đếm lại mới biết mình thiếu gì</a></li><li><a href="/server/privatebin-tren-nas-chia-se-text-co-mat-khau">PrivateBin trên NAS - link chia sẻ text có mật khẩu, không giới hạn 31 ngày</a></li><li><a href="/server/nodewarden-hay-vaultwarden-chot-cai-nao">NodeWarden hay Vaultwarden - chạy song song mấy tháng rồi mình chốt cái nào</a></li><li><a href="/server/nas-het-ram-do-truoc-khi-cai-them">NAS hết RAM: zram đầy 100%, gần 1 GB tràn xuống ổ cứng</a></li><li class="dang-doc" aria-current="true">Kéo 154 repo GitHub về NAS: mirror tự cập nhật bằng Gitea</li></ol></aside>

<p>Bài này là cách mình kéo toàn bộ số repo đó về con NAS ở nhà, tự động cập nhật, kèm script chạy hàng loạt và cái bẫy token đã làm mình mất một buổi.</p>

<h2 id="push-mirror-hay-pull-mirror--nhầm-chiều-là-hỏng">Push mirror hay pull mirror — nhầm chiều là hỏng</h2>

<p>Gitea có hai thứ tên gần giống nhau mà chiều dữ liệu ngược hẳn. Phải phân biệt trước khi bấm bất cứ nút nào.</p>

<table>
  <thead>
    <tr>
      <th> </th>
      <th>Push mirror</th>
      <th>Pull mirror</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Chiều dữ liệu</td>
      <td>Gitea → GitHub</td>
      <td>GitHub → Gitea</td>
    </tr>
    <tr>
      <td>Ai là bản gốc</td>
      <td>Gitea</td>
      <td>GitHub</td>
    </tr>
    <tr>
      <td>Repo bên Gitea</td>
      <td>ghi bình thường</td>
      <td><strong>chỉ đọc</strong> — chặn push, chặn sửa trên web</td>
    </tr>
  </tbody>
</table>

<p>Bài này dùng <strong>pull mirror</strong>: GitHub là bản gốc, Gitea chỉ hứng về.</p>

<p><img src="/assets/images/2026/2026-09-12-gitea-mirror-sofsog.com01.jpg" alt="Hình sơ đồ dòng dữ liệu chảy từ GitHub qua Gitea rồi nằm lại trên NAS sofsog.com" /></p>

<p>Chiều mũi tên trong hình là thứ cần nhớ: dữ liệu chảy từ GitHub sang Gitea rồi nằm lại trên NAS, và <strong>không có chiều ngược lại</strong>. Bạn sửa gì trên bản ở NAS cũng sẽ bị ghi đè ở lần đồng bộ kế tiếp.</p>

<p>Ở đây có một cái bẫy đáng nói. Vault Obsidian của mình đang chạy <strong>ngược lại</strong> — <a href="/server/dung-gitea-tren-nas-dong-bo-obsidian-giua-pc-va-dien-thoai">Gitea trên NAS là hub</a>, máy tính và điện thoại push vào đó rồi Gitea mới đẩy tiếp lên GitHub. Nếu mình lỡ tay bật pull mirror cho cái repo vault đó thì nó thành chỉ đọc, và <strong>mọi commit từ máy sẽ bị chặn</strong>.</p>

<p>Nên việc đầu tiên là ghi tên repo đó vào danh sách loại trừ, trước khi chạy script. Mình sẽ nói ở bước 4.</p>

<h2 id="điều-kiện-cần">Điều kiện cần</h2>

<p>Một Gitea đang chạy — mình dùng bản cài dạng gói trên DSM, <a href="/server/dung-gitea-tren-nas-dong-bo-obsidian-giua-pc-va-dien-thoai">đã viết ở bài đầu series</a>. Một tài khoản GitHub. Và quyền SSH vào NAS để chạy script.</p>

<p>Dung lượng thì cứ tính rộng tay: 154 repo của mình về tới nơi không nặng, nhưng nếu bạn có repo chứa ảnh hay dữ liệu lớn thì cộng lại nhanh hơn tưởng.</p>

<h2 id="bước-1-tạo-token-github-và-cái-bẫy-ở-đây">Bước 1: Tạo token GitHub, và cái bẫy ở đây</h2>

<p>Đây là chỗ mình vấp, và triệu chứng của nó rất khó chịu vì <strong>không có thông báo lỗi nào cả</strong>.</p>

<p>Vào GitHub → Settings → Developer settings → Personal access tokens → <strong>Fine-grained tokens</strong> → Generate new token. Cần đúng <strong>hai</strong> thứ, thiếu một là hỏng:</p>

<ol>
  <li><strong>Repository access</strong> đặt thành <code class="language-plaintext highlighter-rouge">All repositories</code></li>
  <li><strong>Permissions → Repository permissions</strong>: <code class="language-plaintext highlighter-rouge">Contents</code> để <code class="language-plaintext highlighter-rouge">Read-only</code>, và <code class="language-plaintext highlighter-rouge">Metadata</code> để <code class="language-plaintext highlighter-rouge">Read-only</code></li>
</ol>

<p>Cái bẫy nằm ở chỗ: <strong>nếu bạn để phần Permissions trống, GitHub âm thầm đưa Repository access về <code class="language-plaintext highlighter-rouge">Public repositories</code> mỗi lần lưu.</strong> Bấm Update bao nhiêu lần cũng vô ích, quay lại vẫn thấy nó nhảy về Public.</p>

<p>Lý do thì hợp lý khi hiểu ra: loại token này đọc được repo công khai sẵn rồi, nên chọn “All repositories” mà không cấp quyền nào thì chẳng có nghĩa gì. Chỉ là GitHub không nói ra.</p>

<p>Hệ quả nếu để lọt: <strong>script chạy trơn tru, không lỗi, thấy đủ repo công khai — nhưng mọi repo private trả về HTTP 404 như thể không tồn tại.</strong> Mình đã tạo xong 100 mirror rồi mới phát hiện thiếu mất 52 cái.</p>

<p>Kiểm tra nhanh bằng một lệnh, thay tên tài khoản và tên một repo private của bạn:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">-sS</span> <span class="nt">-o</span> /dev/null <span class="nt">-w</span> <span class="s2">"%{http_code}</span><span class="se">\n</span><span class="s2">"</span> <span class="se">\</span>
  <span class="nt">-H</span> <span class="s2">"Authorization: Bearer &lt;token-github&gt;"</span> <span class="se">\</span>
  https://api.github.com/repos/&lt;tài-khoản&gt;/&lt;repo-private&gt;
</code></pre></div></div>

<p>Ra <code class="language-plaintext highlighter-rouge">200</code> là ổn. Ra <code class="language-plaintext highlighter-rouge">404</code> là token chưa đủ quyền — repo vẫn ở đó, chỉ là token không nhìn thấy.</p>

<p>Một điểm tiện: nếu bạn sửa quyền của <strong>token cũ</strong> thì chuỗi token không đổi, không phải nạp lại vào NAS. Chỉ khi tạo token mới mới phải cập nhật.</p>

<h2 id="bước-2-tạo-token-gitea">Bước 2: Tạo token Gitea</h2>

<p>Script cần gọi API của cả hai bên, nên cũng cần một token của chính Gitea.</p>

<p>Trên Gitea: bấm avatar → <strong>Settings</strong> → <strong>Applications</strong> → Generate Token, cấp quyền <code class="language-plaintext highlighter-rouge">repository: Read and Write</code>.</p>

<p>Copy ngay, vì Gitea chỉ hiện một lần.</p>

<h2 id="bước-3-thử-một-repo-bằng-giao-diện-web-trước">Bước 3: Thử một repo bằng giao diện web trước</h2>

<p>Đừng chạy script ngay. Làm tay một repo để biết mọi thứ đúng chưa.</p>

<p>Trên Gitea bấm dấu <strong>+</strong> → <strong>New Migration</strong> → chọn <strong>GitHub</strong>:</p>

<ul>
  <li><strong>Clone From URL</strong>: <code class="language-plaintext highlighter-rouge">https://github.com/&lt;tài-khoản&gt;/&lt;repo&gt;.git</code></li>
  <li><strong>Access Token</strong>: dán token GitHub ở bước 1</li>
  <li>Tick <strong>This repository will be a mirror</strong> — đây chính là công tắc biến nó thành pull mirror</li>
  <li><strong>Mirror Interval</strong>: <code class="language-plaintext highlighter-rouge">8h</code>. Tối thiểu Gitea cho phép là <code class="language-plaintext highlighter-rouge">10m</code>; để trống nghĩa là chỉ đồng bộ khi bấm tay</li>
  <li>Tick <strong>Private</strong></li>
</ul>

<p>Mấy ô Issues, Pull Requests, Labels, Milestones thì nên biết trước: <strong>pull mirror chỉ đồng bộ định kỳ phần git</strong> — nhánh, thẻ, wiki. Những thứ kia nếu tick thì chỉ được sao chép đúng một lần lúc tạo, sau đó đứng im mãi mãi.</p>

<p>Tạo xong, vào repo đó → Settings → <strong>Mirror Settings</strong> để đổi chu kỳ, bấm <strong>Synchronize Now</strong> đồng bộ ngay, hoặc cập nhật token khi hết hạn. Ở đó cũng có nút <strong>Convert to Regular Repository</strong> để gỡ trạng thái mirror — nút này <strong>một chiều, không hoàn tác được</strong>.</p>

<h2 id="bước-4-script-mirror-hàng-loạt">Bước 4: Script mirror hàng loạt</h2>

<p>Làm tay 154 lần thì không ai làm nổi. Đây là script mình đang chạy thật trên NAS, đặt ở <code class="language-plaintext highlighter-rouge">~/scripts/gitea-mirror-all.sh</code> với quyền <code class="language-plaintext highlighter-rouge">700</code>.</p>

<p>Cách nó hoạt động: gọi <code class="language-plaintext highlighter-rouge">/user/repos</code> của GitHub có phân trang để lấy toàn bộ repo mình sở hữu, rồi với từng repo gọi <code class="language-plaintext highlighter-rouge">POST /api/v1/repos/migrate</code> của Gitea kèm <code class="language-plaintext highlighter-rouge">"mirror": true</code>. Repo đã tồn tại bên Gitea sẽ trả về <strong>409</strong> và bị bỏ qua — nên <strong>chạy lại bao nhiêu lần cũng an toàn</strong>.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/usr/bin/env bash</span>
<span class="c"># Dong bo pull mirror tu GitHub ve Gitea tren NAS.</span>
<span class="c">#   bash gitea-mirror-all.sh          -&gt; quet GitHub va tao mirror cho repo moi</span>
<span class="c">#   bash gitea-mirror-all.sh --check  -&gt; chi kiem tra token + dem repo, khong tao gi</span>
<span class="nb">set</span> <span class="nt">-u</span>
<span class="nb">export </span><span class="nv">PATH</span><span class="o">=</span>/usr/bin:/bin:/usr/local/bin:<span class="nv">$PATH</span>

<span class="nv">GITEA_URL</span><span class="o">=</span><span class="s2">"</span><span class="k">${</span><span class="nv">GITEA_URL</span><span class="k">:-</span><span class="nv">http</span>://<span class="p">&lt;địa-chỉ-nas&gt;</span>:8418<span class="k">}</span><span class="s2">"</span>
<span class="nv">GITEA_OWNER</span><span class="o">=</span><span class="s2">"</span><span class="k">${</span><span class="nv">GITEA_OWNER</span><span class="k">:-</span><span class="p">&lt;tài-khoản-gitea&gt;</span><span class="k">}</span><span class="s2">"</span>
<span class="nv">MIRROR_INTERVAL</span><span class="o">=</span><span class="s2">"</span><span class="k">${</span><span class="nv">MIRROR_INTERVAL</span><span class="k">:-</span><span class="nv">8h</span><span class="k">}</span><span class="s2">"</span>

<span class="nv">BASE</span><span class="o">=</span><span class="s2">"</span><span class="si">$(</span><span class="nb">cd</span> <span class="s2">"</span><span class="si">$(</span><span class="nb">dirname</span> <span class="s2">"</span><span class="nv">$0</span><span class="s2">"</span><span class="si">)</span><span class="s2">"</span> <span class="o">&amp;&amp;</span> <span class="nb">pwd</span><span class="si">)</span><span class="s2">"</span>
<span class="nv">ENV_FILE</span><span class="o">=</span><span class="s2">"</span><span class="k">${</span><span class="nv">ENV_FILE</span><span class="k">:-</span><span class="nv">$BASE</span><span class="p">/.gitea-mirror.env</span><span class="k">}</span><span class="s2">"</span>
<span class="nv">SKIP_FILE</span><span class="o">=</span><span class="s2">"</span><span class="nv">$BASE</span><span class="s2">/skip.txt"</span>
<span class="nv">LIST_FILE</span><span class="o">=</span><span class="s2">"</span><span class="nv">$BASE</span><span class="s2">/logs/repos.txt"</span>
<span class="nv">LOG</span><span class="o">=</span><span class="s2">"</span><span class="nv">$BASE</span><span class="s2">/logs/gitea-mirror.log"</span>
<span class="nb">mkdir</span> <span class="nt">-p</span> <span class="s2">"</span><span class="nv">$BASE</span><span class="s2">/logs"</span>

log<span class="o">()</span> <span class="o">{</span> <span class="nv">m</span><span class="o">=</span><span class="s2">"</span><span class="si">$(</span><span class="nb">date</span> <span class="s1">'+%F %T'</span><span class="si">)</span><span class="s2"> </span><span class="nv">$*</span><span class="s2">"</span><span class="p">;</span> <span class="nb">echo</span> <span class="s2">"</span><span class="nv">$m</span><span class="s2">"</span><span class="p">;</span> <span class="nb">echo</span> <span class="s2">"</span><span class="nv">$m</span><span class="s2">"</span> <span class="o">&gt;&gt;</span> <span class="s2">"</span><span class="nv">$LOG</span><span class="s2">"</span><span class="p">;</span> <span class="o">}</span>

<span class="nb">exec </span>9&gt;<span class="s2">"</span><span class="nv">$BASE</span><span class="s2">/logs/.lock"</span>
flock <span class="nt">-n</span> 9 <span class="o">||</span> <span class="o">{</span> log <span class="s2">"Bo qua: dang co tien trinh khac chay"</span><span class="p">;</span> <span class="nb">exit </span>0<span class="p">;</span> <span class="o">}</span>

<span class="o">[</span> <span class="nt">-f</span> <span class="s2">"</span><span class="nv">$ENV_FILE</span><span class="s2">"</span> <span class="o">]</span> <span class="o">||</span> <span class="o">{</span> log <span class="s2">"LOI: thieu file token </span><span class="nv">$ENV_FILE</span><span class="s2">"</span><span class="p">;</span> <span class="nb">exit </span>1<span class="p">;</span> <span class="o">}</span>
<span class="nb">.</span> <span class="s2">"</span><span class="nv">$ENV_FILE</span><span class="s2">"</span>
<span class="k">if</span> <span class="o">[</span> <span class="nt">-z</span> <span class="s2">"</span><span class="k">${</span><span class="nv">GH_TOKEN</span><span class="k">:-}</span><span class="s2">"</span> <span class="o">]</span> <span class="o">||</span> <span class="o">[</span> <span class="nt">-z</span> <span class="s2">"</span><span class="k">${</span><span class="nv">GITEA_TOKEN</span><span class="k">:-}</span><span class="s2">"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then
  </span>log <span class="s2">"LOI: </span><span class="nv">$ENV_FILE</span><span class="s2"> chua co GH_TOKEN / GITEA_TOKEN"</span><span class="p">;</span> <span class="nb">exit </span>1
<span class="k">fi

</span>pick<span class="o">()</span> <span class="o">{</span> <span class="nb">grep</span> <span class="nt">-o</span> <span class="s2">"</span><span class="se">\"</span><span class="nv">$1</span><span class="se">\"</span><span class="s2">[[:space:]]*:[[:space:]]*</span><span class="se">\"</span><span class="s2">[^</span><span class="se">\"</span><span class="s2">]*</span><span class="se">\"</span><span class="s2">"</span> | <span class="nb">sed</span> <span class="s1">'s/.*"\([^"]*\)"$/\1/'</span><span class="p">;</span> <span class="o">}</span>

<span class="nv">gh_user</span><span class="o">=</span><span class="si">$(</span>curl <span class="nt">-sS</span> <span class="nt">--max-time</span> 30 <span class="nt">-H</span> <span class="s2">"Authorization: Bearer </span><span class="nv">$GH_TOKEN</span><span class="s2">"</span> <span class="se">\</span>
  https://api.github.com/user | pick login<span class="si">)</span>
<span class="o">[</span> <span class="nt">-n</span> <span class="s2">"</span><span class="nv">$gh_user</span><span class="s2">"</span> <span class="o">]</span> <span class="o">||</span> <span class="o">{</span> log <span class="s2">"LOI: token GitHub khong hop le hoac het han"</span><span class="p">;</span> <span class="nb">exit </span>1<span class="p">;</span> <span class="o">}</span>
<span class="nv">gt_user</span><span class="o">=</span><span class="si">$(</span>curl <span class="nt">-sS</span> <span class="nt">--max-time</span> 30 <span class="nt">-H</span> <span class="s2">"Authorization: token </span><span class="nv">$GITEA_TOKEN</span><span class="s2">"</span> <span class="se">\</span>
  <span class="s2">"</span><span class="nv">$GITEA_URL</span><span class="s2">/api/v1/user"</span> | pick login<span class="si">)</span>
<span class="o">[</span> <span class="nt">-n</span> <span class="s2">"</span><span class="nv">$gt_user</span><span class="s2">"</span> <span class="o">]</span> <span class="o">||</span> <span class="o">{</span> log <span class="s2">"LOI: token Gitea khong hop le hoac het han"</span><span class="p">;</span> <span class="nb">exit </span>1<span class="p">;</span> <span class="o">}</span>
log <span class="s2">"=== Bat dau: GitHub=</span><span class="nv">$gh_user</span><span class="s2"> -&gt; Gitea=</span><span class="nv">$gt_user</span><span class="s2"> ==="</span>

: <span class="o">&gt;</span> <span class="s2">"</span><span class="nv">$LIST_FILE</span><span class="s2">"</span><span class="p">;</span> <span class="nv">page</span><span class="o">=</span>1
<span class="k">while</span> :<span class="p">;</span> <span class="k">do
  </span><span class="nv">names</span><span class="o">=</span><span class="si">$(</span>curl <span class="nt">-sS</span> <span class="nt">--max-time</span> 60 <span class="nt">-H</span> <span class="s2">"Authorization: Bearer </span><span class="nv">$GH_TOKEN</span><span class="s2">"</span> <span class="se">\</span>
    <span class="s2">"https://api.github.com/user/repos?per_page=100&amp;affiliation=owner&amp;page=</span><span class="nv">$page</span><span class="s2">"</span> | pick full_name<span class="si">)</span>
  <span class="o">[</span> <span class="nt">-z</span> <span class="s2">"</span><span class="nv">$names</span><span class="s2">"</span> <span class="o">]</span> <span class="o">&amp;&amp;</span> <span class="nb">break
  printf</span> <span class="s1">'%s\n'</span> <span class="s2">"</span><span class="nv">$names</span><span class="s2">"</span> <span class="o">&gt;&gt;</span> <span class="s2">"</span><span class="nv">$LIST_FILE</span><span class="s2">"</span>
  <span class="nv">page</span><span class="o">=</span><span class="k">$((</span>page <span class="o">+</span> <span class="m">1</span><span class="k">))</span>
<span class="k">done
</span><span class="nb">sort</span> <span class="nt">-u</span> <span class="nt">-o</span> <span class="s2">"</span><span class="nv">$LIST_FILE</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$LIST_FILE</span><span class="s2">"</span>
<span class="nv">total</span><span class="o">=</span><span class="si">$(</span><span class="nb">grep</span> <span class="nt">-c</span> <span class="nb">.</span> <span class="s2">"</span><span class="nv">$LIST_FILE</span><span class="s2">"</span> <span class="o">||</span> <span class="nb">true</span><span class="si">)</span>
log <span class="s2">"GitHub dang co </span><span class="nv">$total</span><span class="s2"> repo (danh sach: </span><span class="nv">$LIST_FILE</span><span class="s2">)"</span>

<span class="k">if</span> <span class="o">[</span> <span class="s2">"</span><span class="k">${</span><span class="nv">1</span><span class="k">:-}</span><span class="s2">"</span> <span class="o">=</span> <span class="s2">"--check"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then </span>log <span class="s2">"=== Che do --check, khong tao gi ==="</span><span class="p">;</span> <span class="nb">exit </span>0<span class="p">;</span> <span class="k">fi

</span><span class="nv">tmp</span><span class="o">=</span><span class="si">$(</span><span class="nb">mktemp</span><span class="si">)</span><span class="p">;</span> <span class="nv">ok</span><span class="o">=</span>0<span class="p">;</span> <span class="nv">skip</span><span class="o">=</span>0<span class="p">;</span> <span class="nv">err</span><span class="o">=</span>0
<span class="k">while </span><span class="nv">IFS</span><span class="o">=</span> <span class="nb">read</span> <span class="nt">-r</span> full<span class="p">;</span> <span class="k">do
  case</span> <span class="s2">"</span><span class="nv">$full</span><span class="s2">"</span> <span class="k">in</span> <span class="s1">''</span><span class="p">|</span><span class="s1">'#'</span><span class="k">*</span><span class="p">)</span> <span class="k">continue</span> <span class="p">;;</span> <span class="k">esac</span>
  <span class="k">if</span> <span class="o">[</span> <span class="nt">-f</span> <span class="s2">"</span><span class="nv">$SKIP_FILE</span><span class="s2">"</span> <span class="o">]</span> <span class="o">&amp;&amp;</span> <span class="nb">grep</span> <span class="nt">-qxF</span> <span class="s2">"</span><span class="nv">$full</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$SKIP_FILE</span><span class="s2">"</span> 2&gt;/dev/null<span class="p">;</span> <span class="k">then
    </span><span class="nv">skip</span><span class="o">=</span><span class="k">$((</span>skip <span class="o">+</span> <span class="m">1</span><span class="k">))</span><span class="p">;</span> <span class="k">continue
  fi
  </span><span class="nv">name</span><span class="o">=</span><span class="s2">"</span><span class="k">${</span><span class="nv">full</span><span class="p">##*/</span><span class="k">}</span><span class="s2">"</span>
  <span class="nv">code</span><span class="o">=</span><span class="si">$(</span>curl <span class="nt">-sS</span> <span class="nt">-o</span> <span class="s2">"</span><span class="nv">$tmp</span><span class="s2">"</span> <span class="nt">-w</span> <span class="s1">'%{http_code}'</span> <span class="nt">--max-time</span> 1800 <span class="se">\</span>
    <span class="nt">-X</span> POST <span class="s2">"</span><span class="nv">$GITEA_URL</span><span class="s2">/api/v1/repos/migrate"</span> <span class="se">\</span>
    <span class="nt">-H</span> <span class="s2">"Authorization: token </span><span class="nv">$GITEA_TOKEN</span><span class="s2">"</span> <span class="nt">-H</span> <span class="s2">"Content-Type: application/json"</span> <span class="se">\</span>
    <span class="nt">-d</span> <span class="s2">"{</span><span class="se">\"</span><span class="s2">clone_addr</span><span class="se">\"</span><span class="s2">:</span><span class="se">\"</span><span class="s2">https://github.com/</span><span class="nv">$full</span><span class="s2">.git</span><span class="se">\"</span><span class="s2">,</span><span class="se">\"</span><span class="s2">auth_token</span><span class="se">\"</span><span class="s2">:</span><span class="se">\"</span><span class="nv">$GH_TOKEN</span><span class="se">\"</span><span class="s2">,</span><span class="se">\"</span><span class="s2">repo_owner</span><span class="se">\"</span><span class="s2">:</span><span class="se">\"</span><span class="nv">$GITEA_OWNER</span><span class="se">\"</span><span class="s2">,</span><span class="se">\"</span><span class="s2">repo_name</span><span class="se">\"</span><span class="s2">:</span><span class="se">\"</span><span class="nv">$name</span><span class="se">\"</span><span class="s2">,</span><span class="se">\"</span><span class="s2">service</span><span class="se">\"</span><span class="s2">:</span><span class="se">\"</span><span class="s2">github</span><span class="se">\"</span><span class="s2">,</span><span class="se">\"</span><span class="s2">mirror</span><span class="se">\"</span><span class="s2">:true,</span><span class="se">\"</span><span class="s2">mirror_interval</span><span class="se">\"</span><span class="s2">:</span><span class="se">\"</span><span class="nv">$MIRROR_INTERVAL</span><span class="se">\"</span><span class="s2">,</span><span class="se">\"</span><span class="s2">private</span><span class="se">\"</span><span class="s2">:true,</span><span class="se">\"</span><span class="s2">wiki</span><span class="se">\"</span><span class="s2">:true,</span><span class="se">\"</span><span class="s2">description</span><span class="se">\"</span><span class="s2">:</span><span class="se">\"</span><span class="s2">Pull mirror: </span><span class="nv">$full</span><span class="se">\"</span><span class="s2">}"</span><span class="si">)</span>
  <span class="k">case</span> <span class="s2">"</span><span class="nv">$code</span><span class="s2">"</span> <span class="k">in
    </span>201<span class="p">)</span> <span class="nv">ok</span><span class="o">=</span><span class="k">$((</span>ok <span class="o">+</span> <span class="m">1</span><span class="k">))</span><span class="p">;</span> log <span class="s2">"TAO MOI  </span><span class="nv">$full</span><span class="s2">"</span> <span class="p">;;</span>
    409<span class="p">)</span> <span class="nv">skip</span><span class="o">=</span><span class="k">$((</span>skip <span class="o">+</span> <span class="m">1</span><span class="k">))</span> <span class="p">;;</span>
    <span class="k">*</span><span class="p">)</span>   <span class="nv">err</span><span class="o">=</span><span class="k">$((</span>err <span class="o">+</span> <span class="m">1</span><span class="k">))</span><span class="p">;</span> log <span class="s2">"LOI </span><span class="nv">$code</span><span class="s2">  </span><span class="nv">$full</span><span class="s2"> : </span><span class="si">$(</span><span class="nb">head</span> <span class="nt">-c</span> 200 <span class="s2">"</span><span class="nv">$tmp</span><span class="s2">"</span> | <span class="nb">tr</span> <span class="nt">-d</span> <span class="s1">'\n'</span><span class="si">)</span><span class="s2">"</span> <span class="p">;;</span>
  <span class="k">esac</span>
<span class="k">done</span> &lt; <span class="s2">"</span><span class="nv">$LIST_FILE</span><span class="s2">"</span>
<span class="nb">rm</span> <span class="nt">-f</span> <span class="s2">"</span><span class="nv">$tmp</span><span class="s2">"</span>

log <span class="s2">"=== Xong: tao moi=</span><span class="nv">$ok</span><span class="s2">, da co/bo qua=</span><span class="nv">$skip</span><span class="s2">, loi=</span><span class="nv">$err</span><span class="s2"> ==="</span>
<span class="k">if</span> <span class="o">[</span> <span class="s2">"</span><span class="si">$(</span><span class="nb">wc</span> <span class="nt">-l</span> &lt; <span class="s2">"</span><span class="nv">$LOG</span><span class="s2">"</span><span class="si">)</span><span class="s2">"</span> <span class="nt">-gt</span> 5000 <span class="o">]</span><span class="p">;</span> <span class="k">then </span><span class="nb">tail</span> <span class="nt">-2000</span> <span class="s2">"</span><span class="nv">$LOG</span><span class="s2">"</span> <span class="o">&gt;</span> <span class="s2">"</span><span class="nv">$LOG</span><span class="s2">.tmp"</span> <span class="o">&amp;&amp;</span> <span class="nb">mv</span> <span class="s2">"</span><span class="nv">$LOG</span><span class="s2">.tmp"</span> <span class="s2">"</span><span class="nv">$LOG</span><span class="s2">"</span><span class="p">;</span> <span class="k">fi
</span><span class="nb">exit </span>0
</code></pre></div></div>

<p>Vài chỗ trong script đáng giải thích:</p>

<p><strong><code class="language-plaintext highlighter-rouge">flock -n 9</code></strong> khoá không cho hai lần chạy chồng lên nhau. Chạy theo lịch định kỳ mà lần trước còn đang tải dở thì lần sau tự thoát, không đánh nhau.</p>

<p><strong><code class="language-plaintext highlighter-rouge">--max-time 1800</code></strong> cho lệnh migrate là ba mươi phút cho mỗi repo. Nghe dài, nhưng Gitea clone repo lớn có thể lâu và cắt sớm thì hỏng dở dang.</p>

<p><strong><code class="language-plaintext highlighter-rouge">affiliation=owner</code></strong> giới hạn ở repo mình sở hữu, không kéo về những repo mình chỉ được mời cộng tác.</p>

<p><strong>Mã trả về</strong> là toàn bộ logic: <code class="language-plaintext highlighter-rouge">201</code> là tạo mới, <code class="language-plaintext highlighter-rouge">409</code> là đã có nên bỏ qua, còn lại là lỗi và được ghi log kèm 200 ký tự đầu của phản hồi.</p>

<p>Script đọc token từ file riêng, không nhúng trong mã. Tạo file đó <strong>trên NAS</strong>, bằng cách gõ vào chứ đừng để token nằm trong lịch sử lệnh:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">read</span> <span class="nt">-rsp</span> <span class="s2">"GitHub token: "</span> G<span class="p">;</span> <span class="nb">echo
read</span> <span class="nt">-rsp</span> <span class="s2">"Gitea token : "</span> T<span class="p">;</span> <span class="nb">echo
umask </span>077
<span class="nb">printf</span> <span class="s1">'export GH_TOKEN=%s\nexport GITEA_TOKEN=%s\n'</span> <span class="s2">"</span><span class="nv">$G</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$T</span><span class="s2">"</span> <span class="o">&gt;</span> ~/scripts/.gitea-mirror.env
<span class="nb">chmod </span>600 ~/scripts/.gitea-mirror.env
</code></pre></div></div>

<p>Rồi tạo danh sách loại trừ — <strong>đây là bước bảo vệ repo vault nói ở đầu bài</strong>, mỗi dòng một <code class="language-plaintext highlighter-rouge">tài-khoản/repo</code>:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">echo</span> <span class="s2">"&lt;tài-khoản&gt;/&lt;repo-vault&gt;"</span> <span class="o">&gt;&gt;</span> ~/scripts/skip.txt
</code></pre></div></div>

<p>Chạy thử ở chế độ kiểm tra trước, nó chỉ xác thực token và đếm repo chứ không tạo gì:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>bash ~/scripts/gitea-mirror-all.sh <span class="nt">--check</span>
</code></pre></div></div>

<p>Thấy đúng số repo mình có thì chạy thật:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>bash ~/scripts/gitea-mirror-all.sh
</code></pre></div></div>

<h2 id="bước-5-đặt-lịch-chạy-hàng-tuần">Bước 5: Đặt lịch chạy hàng tuần</h2>

<p>Đây là chỗ nhiều người bỏ sót. <strong>Gitea không có chức năng mirror cả một tài khoản.</strong> Mỗi mirror là một repo được tạo riêng. Repo bạn tạo mới trên GitHub ngày mai sẽ không tự về NAS — phải chạy lại script.</p>

<p>Mình đặt <strong>hàng tuần</strong>. Hàng tháng cũng chạy được, nhưng một repo mới có thể nằm ngoài bản sao tới ba mươi ngày, mà chi phí chạy thêm gần như bằng không: lần chạy khi không có repo mới chỉ mất hơn một phút và không tạo ra gì.</p>

<p>Trên DSM: <strong>Control Panel → Task Scheduler → Create → Scheduled Task → User-defined script</strong></p>

<table>
  <thead>
    <tr>
      <th>Trường</th>
      <th>Giá trị</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Task name</td>
      <td><code class="language-plaintext highlighter-rouge">Gitea mirror GitHub</code></td>
    </tr>
    <tr>
      <td>User</td>
      <td>tài khoản có thư mục <code class="language-plaintext highlighter-rouge">scripts</code></td>
    </tr>
    <tr>
      <td>Schedule → Date</td>
      <td>Repeat <strong>Weekly</strong>, chọn một ngày cố định trong tuần</td>
    </tr>
    <tr>
      <td>First run time</td>
      <td><code class="language-plaintext highlighter-rouge">03:00</code></td>
    </tr>
    <tr>
      <td>Run command</td>
      <td><code class="language-plaintext highlighter-rouge">/bin/bash /var/services/homes/&lt;user&gt;/scripts/gitea-mirror-all.sh</code></td>
    </tr>
  </tbody>
</table>

<p>Dùng Task Scheduler của DSM chứ <strong>đừng viết vào <code class="language-plaintext highlighter-rouge">/etc/crontab</code></strong> — DSM có thể ghi đè tệp đó khi cập nhật hệ thống, và bạn sẽ mất lịch mà không biết.</p>

<h2 id="kiểm-tra-bằng-cơ-sở-dữ-liệu-của-gitea">Kiểm tra bằng cơ sở dữ liệu của Gitea</h2>

<p>Giao diện web không có chỗ nào xem được toàn bộ mirror cùng lúc. Nhưng Gitea dùng SQLite nên đọc thẳng được. Luôn thêm <code class="language-plaintext highlighter-rouge">-readonly</code>, đừng ghi vào đó.</p>

<p>Đếm nhanh — bảng <code class="language-plaintext highlighter-rouge">mirror</code> là pull mirror, <code class="language-plaintext highlighter-rouge">push_mirror</code> là push mirror:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlite3 <span class="nt">-readonly</span> /volume1/@appdata/gitea/data/gitea.db <span class="se">\</span>
  <span class="s2">"SELECT count(*) FROM mirror; SELECT count(*) FROM push_mirror;"</span>
</code></pre></div></div>

<p>Xem chu kỳ và lần đồng bộ gần nhất của từng cái:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlite3 <span class="nt">-readonly</span> <span class="nt">-header</span> <span class="nt">-column</span> /volume1/@appdata/gitea/data/gitea.db <span class="se">\</span>
  <span class="s2">"SELECT r.owner_name||'/'||r.name AS repo,
          (m.interval/3600000000000)||'h' AS chu_ky,
          datetime(m.updated_unix,'unixepoch','localtime') AS lan_cuoi,
          datetime(m.next_update_unix,'unixepoch','localtime') AS lan_toi
   FROM mirror m JOIN repository r ON r.id = m.repo_id;"</span>
</code></pre></div></div>

<p>Cột <code class="language-plaintext highlighter-rouge">interval</code> lưu bằng nanô giây, nên phải chia cho 3.600.000.000.000 mới ra giờ.</p>

<p>Và câu truy vấn mình thấy hữu ích nhất — tìm repo nằm trên Gitea nhưng <strong>không phải mirror</strong>, tức là sẽ không bao giờ tự cập nhật:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlite3 <span class="nt">-readonly</span> /volume1/@appdata/gitea/data/gitea.db <span class="se">\</span>
  <span class="s2">"SELECT r.name FROM repository r
   LEFT JOIN mirror m ON m.repo_id = r.id
   WHERE m.id IS NULL;"</span>
</code></pre></div></div>

<p>Chính câu này chỉ ra cho mình một repo mình từng clone tay từ lâu. Vì nó trùng tên với repo trên GitHub nên script luôn nhận <code class="language-plaintext highlighter-rouge">409</code> và bỏ qua, nghĩa là nó nằm đó như một bản chụp chết cứng từ nhiều tháng trước mà mình cứ tưởng đang được cập nhật. Đó đúng là loại sai lầm mà <a href="/server/quy-tac-3-2-1-lam-cho-that">bài quy tắc 3-2-1</a> nói tới: có bản sao không bằng có bản sao còn sống.</p>

<p>Log của Gitea ở <code class="language-plaintext highlighter-rouge">/volume1/@appdata/gitea/gitea.log</code> nếu cần đào sâu hơn.</p>

<h2 id="những-gì-cách-này-không-làm-được">Những gì cách này không làm được</h2>

<p><strong>Không phải tức thời.</strong> Mỗi mirror đặt chu kỳ 8 tiếng. Gitea có một cron nội bộ tên <code class="language-plaintext highlighter-rouge">update_mirrors</code> chạy mười phút một lần, quét xem mirror nào tới hạn thì <code class="language-plaintext highlighter-rouge">git fetch --prune</code>. Nên commit mới trên GitHub về tới NAS chậm nhất sau tám tiếng.</p>

<p><strong>Đây là polling, không phải webhook.</strong> GitHub hoàn toàn không biết con NAS tồn tại. Muốn gần như tức thời bằng webhook thì không làm được, vì NAS nằm sau <a href="/server/tailscale-vao-nas-tu-xa-khong-mo-port">Tailscale</a> và GitHub không gọi vào được. Đây là cái giá phải trả cho việc không mở cổng nào ra Internet, và mình thấy đổi vậy là đáng.</p>

<p><strong>NAS phải đang bật.</strong> Tắt máy đúng lúc tới hạn thì lần đó bị lỡ, chạy bù sau khi bật lại.</p>

<p><strong>Chỉ có phần git.</strong> Issue, pull request, nhãn, mốc — không đồng bộ định kỳ. Nếu chúng quan trọng với bạn thì đây không phải giải pháp đủ.</p>

<p><strong>Xoá bên GitHub là xoá bên này.</strong> <code class="language-plaintext highlighter-rouge">git fetch --prune</code> nghĩa là nhánh bị xoá trên GitHub cũng biến mất khỏi bản mirror. Nó là bản sao trung thực, <strong>không phải bản lưu trữ chống xoá nhầm</strong>. Muốn chống xoá nhầm thì cần snapshot theo thời điểm, là chuyện khác.</p>

<h2 id="kết-quả">Kết quả</h2>

<p>GitHub của mình lúc thiết lập có <strong>101 repo công khai và 53 repo riêng tư, tổng 154</strong>.</p>

<p>Đợt chạy đầu tạo được 100 mirror — đúng lúc token còn chưa nhìn thấy repo private. Sửa quyền token rồi chạy lại, đợt hai tạo thêm 52 cái, <strong>hết 11 phút, không lỗi nào</strong>.</p>

<p>Đếm lại trên Gitea hôm nay: <strong>152 pull mirror</strong>, cộng repo vault đang chạy push mirror theo chiều ngược lại, cộng một repo thường — vừa đúng 154, khớp 1:1 với GitHub.</p>

<p>Từ giờ mỗi tuần script tự chạy một lần để hứng repo mới, còn repo cũ thì tự cập nhật mỗi tám tiếng. Mình không phải làm gì nữa.</p>

<p>Chúc các bạn thành công.</p>

<h2 id="link-tham-khảo">Link tham khảo</h2>

<p><a href="https://docs.gitea.com/usage/repo-mirror">https://docs.gitea.com/usage/repo-mirror</a></p>

<p><a href="https://docs.gitea.com/api/1.20/">https://docs.gitea.com/api/1.20/</a></p>

<p><a href="https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens">https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens</a></p>]]></content><author><name>Thành</name></author><category term="server" /><category term="thu-thuat-chung" /><category term="Gitea" /><category term="GitHub" /><category term="NAS" /><category term="backup" /><category term="mirror" /><category term="API" /><summary type="html"><![CDATA[Toàn bộ 154 repo của mình nằm trên một tài khoản GitHub duy nhất. Bài này là cách dùng **Pull Mirror** của Gitea kéo hết về NAS làm bản sao tự cập nhật — kèm script chạy hàng loạt, và cái bẫy token khiến repo private trả về **404** mà không báo lỗi gì.]]></summary></entry><entry><title type="html">Lạm phát 30 năm: tiền mất giá là thiết kế, nên mình mua tài sản dần</title><link href="https://sofsog.com/tai-chinh/lam-phat-30-nam-tien-mat-gia-la-thiet-ke" rel="alternate" type="text/html" title="Lạm phát 30 năm: tiền mất giá là thiết kế, nên mình mua tài sản dần" /><published>2026-09-11T00:00:00+00:00</published><updated>2026-09-11T00:00:00+00:00</updated><id>https://sofsog.com/tai-chinh/lam-phat-30-nam-tien-mat-gia-la-thiet-ke</id><content type="html" xml:base="https://sofsog.com/tai-chinh/lam-phat-30-nam-tien-mat-gia-la-thiet-ke"><![CDATA[<p>Một trăm nghìn đồng năm 1996, tính theo rổ hàng tiêu dùng, hôm nay mua được bằng khoảng <strong>hai mươi nghìn năm trăm đồng</strong>.</p>

<p>Đó không phải tai nạn. Đó là thiết kế, và nó được công bố công khai.</p>

<aside class="series-box" aria-label="Các bài trong series Đầu tư dài hạn"><p class="series-box__dau">Series <a href="/series/">Đầu tư dài hạn</a> &middot; bài 1/4 <span class="series-box__cap">Cơ bản</span></p><ol class="series-box__ds"><li class="dang-doc" aria-current="true">Lạm phát 30 năm: tiền mất giá là thiết kế, nên mình mua tài sản dần</li><li><a href="/tai-chinh/bot-vang-thang-lai-20-phan-tram-roi-tai-khoan-ve-0">Bot vàng của mình có tháng lãi 20%, rồi tài khoản về 0</a></li><li><a href="/tai-chinh/danh-muc-dai-han-83-phan-tram-van-nam-o-tien-mat">Danh mục dài hạn của mình: 83% vẫn đang nằm ở tiền mặt</a></li><li><a href="/tai-chinh/mua-vang-sjc-dat-hai-cuoc-nen-minh-chon-paxg">Mua vàng SJC là đặt hai cược cùng lúc, nên mình chọn PAXG</a></li></ol></aside>

<p>Bài này là ghi chép của mình sau khi ngồi tra số liệu ba mươi năm của cả hai đồng tiền, và nó là nền cho mọi thứ còn lại trong loạt bài này — lý do mình mua tài sản dần đều thay vì để dành.</p>

<h2 id="ba-mươi-năm-hai-đồng-tiền">Ba mươi năm, hai đồng tiền</h2>

<p>Từ 1996 tới 2025:</p>

<table>
  <thead>
    <tr>
      <th> </th>
      <th>Đô la Mỹ</th>
      <th>Tiền đồng</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Lạm phát trung bình mỗi năm</td>
      <td>2,52%</td>
      <td><strong>5,43%</strong></td>
    </tr>
    <tr>
      <td>Giá cả tích luỹ</td>
      <td>×2,11</td>
      <td><strong>×4,89</strong></td>
    </tr>
    <tr>
      <td>Sức mua còn lại</td>
      <td>47,4%</td>
      <td><strong>20,5%</strong></td>
    </tr>
  </tbody>
</table>

<p>Con số trung bình che đi những năm khủng khiếp. Việt Nam có <strong>23,1% năm 2008</strong> và <strong>18,7% năm 2011</strong>. Mỹ có 8,0% năm 2022, cao nhất trong bốn thập kỷ nhưng vẫn chưa bằng một năm trung bình xấu của Việt Nam.</p>

<p>Mười năm gần đây thì tiền đồng ổn định hơn hẳn: từ 2015 tới 2025 CPI Việt Nam gần như luôn nằm trong khoảng 0,6% tới 4,1%. Đó là thành tựu thật và không nên bỏ qua khi nói chuyện lạm phát.</p>

<h2 id="số-liệu-chính-thức-không-bị-bịa">Số liệu chính thức không bị bịa</h2>

<p>Mình muốn nói rõ chỗ này trước khi nói phần còn lại, vì nếu bỏ qua nó thì cả bài thành một bài thuyết âm mưu.</p>

<p>Có một cách kiểm chứng chéo rất gọn, không cần tin ai. Năm 1996 tỷ giá khoảng <strong>11.000 đồng một đô</strong>, hôm nay khoảng <strong>26.300</strong>. Giá cả ở Mỹ trong ba mươi năm đó tăng ×2,11.</p>

<p>Vậy để mua đúng cái rổ hàng Mỹ mà 11.000 đồng mua được năm 1996, hôm nay cần:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>2,11 × 26.300 ≈ 55.500 đồng  →  hệ số ×5,05
</code></pre></div></div>

<p>Còn CPI Việt Nam công bố là <strong>×4,89</strong>. Hai con số đi từ hai nguồn hoàn toàn độc lập — một bên là rổ hàng trong nước, một bên là tỷ giá cộng lạm phát Mỹ — mà <strong>lệch nhau 3% sau ba mươi năm</strong>.</p>

<p>Nên những con số kiểu “lạm phát thật ra là 15% một năm” là sai về mặt số học. Nếu Mỹ thật sự lạm phát 8% mỗi năm suốt ba mươi năm thì GDP thực của họ phải âm liên tục hai mươi lăm năm, mâu thuẫn với mọi dữ liệu đếm được bằng vật chất: sản lượng điện, số container, số căn nhà xây mới.</p>

<p>Và đây là chỗ thú vị: <strong>cảm giác “lạm phát thật tệ hơn số liệu” vẫn đúng.</strong> Chỉ là nó đúng vì một lý do khác.</p>

<h2 id="cung-tiền-gấp-300-lần-rổ-hàng-gấp-49-lần">Cung tiền gấp 300 lần, rổ hàng gấp 4,9 lần</h2>

<p><img src="/assets/images/2026/2026-09-11-lam-phat-30-nam-sofsog.com01.png" alt="Hình biểu đồ hệ số tăng của cung tiền, GDP, vàng, nhà và CPI từ 1996 tới 2025 sofsog.com" /></p>

<p>Cùng ba mươi năm đó: cung tiền M2 của Việt Nam tăng khoảng <strong>300 lần</strong>, GDP danh nghĩa tăng <strong>45 lần</strong>, còn rổ hàng CPI chỉ tăng <strong>4,9 lần</strong>.</p>

<p>Phần chênh khổng lồ đó không bốc hơi. Nó chảy vào <strong>giá tài sản</strong>: vàng SJC ×31, chung cư Hà Nội ×20 trở lên.</p>

<p>Và đây là điểm mấu chốt: <strong>CPI theo thiết kế không đo giá tài sản.</strong> Giá mua nhà bị loại khỏi rổ CPI ở mọi quốc gia, vì theo định nghĩa thống kê mua nhà là <em>đầu tư</em> chứ không phải <em>tiêu dùng</em>. CPI chỉ tính tiền thuê nhà.</p>

<p>Nói cách khác: <strong>CPI đo chi phí mua lại cái rổ hàng cũ. Nó không đo chi phí để giữ nguyên vị thế của mình trong xã hội.</strong> Hai thứ đó đã tách nhau ra rất xa.</p>

<h3 id="ba-lý-do-nữa-khiến-con-số-thấy-nhẹ-hơn-đời-sống">Ba lý do nữa khiến con số thấy nhẹ hơn đời sống</h3>

<p><strong>Trọng số nhà ở quá nhẹ.</strong> Nhóm nhà ở, điện nước và vật liệu chiếm khoảng 18,8% rổ hàng, mà phần chỗ ở trong đó thực chất chỉ là tiền thuê. Người trẻ ở Hà Nội chi bốn tới năm mươi phần trăm thu nhập cho chỗ ở. Với đúng nhóm chịu thiệt nhất thì rổ hàng cân sai.</p>

<p><strong>Thay thế và điều chỉnh chất lượng.</strong> Thịt bò lên giá thì thống kê giả định người ta chuyển sang thịt lợn, rổ hàng không tăng nhưng mức sống đã giảm. Điện thoại mạnh gấp đôi mà cùng giá thì được ghi nhận là <em>giảm giá một nửa</em>. Đúng về lý thuyết, nhưng không ai ăn được con chip nhanh hơn.</p>

<p><strong>Giá do Nhà nước điều tiết.</strong> Điện, xăng, học phí, viện phí được điều chỉnh theo lộ trình do cơ quan quản lý quyết định chứ không thả theo thị trường từng ngày. Con số năm 2025 cho thấy hệ quả: CPI chung tăng 3,31%, nhưng <strong>nhóm nhà ở và điện nước tăng 6,08%, riêng điện sinh hoạt tăng 7,20%</strong> — gấp đôi chỉ số chung. Người thuê nhà và trả tiền điện cảm nhận con số thứ hai, không phải con số thứ nhất.</p>

<h3 id="lý-do-quan-trọng-nhất-tiền-mới-không-đến-với-mọi-người-cùng-lúc">Lý do quan trọng nhất: tiền mới không đến với mọi người cùng lúc</h3>

<p>Tiền mới đi vào hệ thống qua kênh tín dụng ngân hàng. Nó đến tay doanh nghiệp lớn, chủ đất, và người vay được vốn <strong>trước tiên</strong> — những người này tiêu ở mặt bằng giá <em>cũ</em>.</p>

<p>Đến lượt người làm công ăn lương thì giá đã tăng rồi.</p>

<p>Nghĩa là <strong>lạm phát không phải một thứ thuế phẳng chia đều cho mọi người. Nó là một cuộc chuyển giao tài sản từ người nhận tiền sau sang người nhận tiền trước.</strong> CPI là con số trung bình nên nó che giấu hoàn toàn cơ chế này. Bạn nhìn vào 3,31% và thấy nhẹ nhàng, trong khi khoảng cách giữa bạn và căn nhà bạn muốn mua đang giãn ra mỗi năm.</p>

<h2 id="mất-giá-là-mục-tiêu-chính-sách-không-phải-sự-cố">Mất giá là mục tiêu chính sách, không phải sự cố</h2>

<p>Chỗ này nhiều người hiểu sai theo hướng âm mưu, nên nói cho đúng.</p>

<p>Fed, Ngân hàng Trung ương châu Âu, Nhật, Anh đều đặt mục tiêu lạm phát <strong>+2%, không phải 0%</strong>. Việt Nam đặt mục tiêu dưới 4 tới 4,5%. Nghĩa là đồng tiền mất giá đúng theo kế hoạch <strong>chính là thành công của chính sách</strong>. Lạm phát về 0 thì ngân hàng trung ương sẽ nới lỏng để đẩy nó lên lại.</p>

<p>Lý do thì có thật và không phải để hại ai: giảm phát kéo dài tệ hơn nhiều. Giá giảm thì người ta hoãn mua, doanh nghiệp giảm doanh thu rồi sa thải, giá trị thực của các khoản nợ phình lên, dẫn tới vỡ nợ dây chuyền. Mỹ những năm 1930 và Nhật từ 1990 tới 2010 là hai ví dụ đắt giá. <strong>Mục tiêu 2% là lựa chọn cái ít tệ hơn, có lập luận đàng hoàng.</strong></p>

<p>Chỉ có điều, với người cầm tiền mặt thì hệ quả giống hệt nhau dù lý do tốt đẹp tới đâu.</p>

<p>Thêm hai chuyện cấu trúc đáng biết. Phần lớn tiền trong nền kinh tế được sinh ra khi ngân hàng thương mại cho vay, nên cung tiền không co lại được mà tổng nợ phải tăng liên tục. Và chính phủ ở mọi nước đều là con nợ lớn nhất, nên lạm phát bào mòn giá trị thực của nợ công — <strong>một khoản thuế không cần Quốc hội thông qua và không hiện trên bảng lương của ai cả.</strong></p>

<p>Có đổi được không? Ba lối ra trên lý thuyết là quay lại bản vị vàng, cạnh tranh tiền tệ tư nhân, hoặc tái lập hệ thống sau một cuộc khủng hoảng lớn. Không cái nào nằm trong khung thời gian tài chính của một đời người. Nên mình lập kế hoạch như thể nó sẽ không đổi.</p>

<h2 id="việc-đầu-tiên-không-tốn-đồng-nào-đổi-thước-đo">Việc đầu tiên không tốn đồng nào: đổi thước đo</h2>

<p>Trước khi bàn mua gì, có một việc nên làm mà không mất tiền.</p>

<p><strong>Ngừng đo tài sản bằng tiền đồng.</strong> Đo bằng số chỉ vàng, số mét vuông đất ở khu mình muốn ở, số đô la, hoặc số tháng chi tiêu mà mình cầm cự được.</p>

<p>Đo bằng tiền đồng thì số dư tài khoản luôn tăng và ta luôn thấy yên tâm. Đổi sang đo bằng mét vuông đất, nhiều người phát hiện mình <strong>thụt lùi suốt mười năm</strong> dù số dư đã gấp ba.</p>

<p>Không đổi thước đo thì không nhìn thấy vấn đề. Không nhìn thấy thì không sửa.</p>

<h2 id="ngưỡng-hoàn-vốn-thật-không-phải-35">Ngưỡng hoàn vốn thật không phải 3,5%</h2>

<p>Từ đó suy ra một bảng mà mình nghĩ ai cũng nên tự làm cho mình:</p>

<table>
  <thead>
    <tr>
      <th>Muốn giữ được gì</th>
      <th>Cần lợi suất khoảng</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Giữ nguyên mức tiêu dùng cũ</td>
      <td>~3,5% (bằng CPI)</td>
    </tr>
    <tr>
      <td>Giữ sức mua quốc tế</td>
      <td>~5–6% (CPI cộng trượt tỷ giá)</td>
    </tr>
    <tr>
      <td><strong>Giữ nguyên vị thế tài sản</strong></td>
      <td><strong>~10–12%</strong></td>
    </tr>
  </tbody>
</table>

<p>Phần lớn mọi người tính theo dòng đầu tiên nhưng sống theo dòng cuối cùng. Gửi tiết kiệm 5–6% thì thắng CPI, nhưng <strong>thua xa tốc độ tăng của giá nhà và giá vàng</strong>. Đó chính là lý do một người cần kiệm cả đời vẫn thấy căn nhà ngày càng xa tầm với, mà không hiểu mình đã làm sai ở đâu. Họ không làm sai gì cả. Họ chỉ dùng sai thước đo.</p>

<h2 id="vì-sao-mình-mua-tài-sản-dần-và-mua-thứ-gì">Vì sao mình mua tài sản dần, và mua thứ gì</h2>

<p>Đây là chỗ toàn bộ phần trên dẫn tới.</p>

<p><strong>Tiền mặt là công cụ, không phải nơi trú ẩn.</strong> Giữ đủ sáu tới mười hai tháng chi tiêu cộng một phần cho cơ hội. Vượt quá mức đó là tự nguyện đóng thuế lạm phát. Mình viết câu này trong lúc <a href="/tai-chinh/danh-muc-dai-han-83-phan-tram-van-nam-o-tien-mat">83% tài sản của chính mình vẫn đang nằm ở tiền mặt</a> — biết và làm được là hai chuyện khác nhau, và bài này chính là thứ nhắc mình phải đi cho xong.</p>

<p><strong>Sở hữu thứ không in thêm được.</strong> Đất, vàng, và với người chịu được rủi ro rất cao thì Bitcoin. Cái chung của chúng là nguồn cung không nở ra theo ý muốn của ai.</p>

<p><strong>Nhưng ưu tiên thứ vừa khan hiếm vừa có dòng tiền.</strong> Đất trống và vàng chỉ <em>giữ chỗ</em> cho bạn — chúng không tạo ra gì. Cổ phần doanh nghiệp thì khác: một doanh nghiệp có <strong>quyền định giá</strong>, tức tăng giá bán theo lạm phát mà không mất khách, vừa giữ chỗ vừa sinh lời. Đó là loại tài sản tốt nhất trong môi trường lạm phát, và cũng là loại khó chọn nhất.</p>

<p>Nên phần lớn danh mục của mình là <strong>cổ phiếu</strong>, phần nhỏ hơn là <strong>Bitcoin</strong> cho vai trò khan hiếm tuyệt đối, và một phần vàng để phòng thủ — vàng thì mình chọn PAXG, <a href="/tai-chinh/mua-vang-sjc-dat-hai-cuoc-nen-minh-chon-paxg">lý do viết riêng ở bài này</a>.</p>

<p>Còn <strong>vì sao mua dần chứ không mua một lần</strong>, thì đó là bài học mình trả học phí mới có: mình không biết hôm nay là đỉnh hay đáy của bất kỳ thứ gì. <a href="/tai-chinh/bot-vang-thang-lai-20-phan-tram-roi-tai-khoan-ve-0">Con bot giao dịch của mình từng lãi 42% một năm rồi về 0</a> đúng vì mình tưởng mình biết. Mua đều theo lịch là cách duy nhất mình còn tin sau chuyện đó.</p>

<p>Có một điều mình muốn cảnh báo riêng cho người Việt đọc các bài tài chính dịch từ tiếng Anh. Lời khuyên “vay dài hạn lãi suất cố định là cách short đồng tiền pháp định” <strong>không áp dụng được ở Việt Nam</strong>. Khoản vay kiểu Mỹ cố định lãi suất ba mươi năm gần như không tồn tại ở đây; hầu hết hợp đồng chỉ ưu đãi cố định một hai năm rồi thả nổi. Đừng bê logic đó về mà không đọc kỹ điều khoản điều chỉnh lãi suất.</p>

<h2 id="thứ-quan-trọng-hơn-cả-danh-mục">Thứ quan trọng hơn cả danh mục</h2>

<p>Với phần lớn mọi người, <strong>tài sản lớn nhất không phải danh mục đầu tư mà là năng lực tạo ra thu nhập.</strong></p>

<p>Người có thu nhập tự tái định giá theo lạm phát — nhờ kỹ năng khan hiếm, doanh nghiệp riêng, hay hợp đồng có điều khoản trượt giá — được bảo vệ tốt hơn nhiều so với người có hai tỷ gửi tiết kiệm và một công việc lương cố định.</p>

<p>Đây là lý do “mua vàng đi” là một câu trả lời kém. Vàng bảo vệ số tiền bạn đã có. Nó không bảo vệ <strong>dòng tiền tương lai</strong> của bạn, mà với hầu hết mọi người thì dòng tiền tương lai mới là phần lớn giá trị ròng.</p>

<h2 id="cạm-bẫy-nằm-ngay-sau-bài-viết-này">Cạm bẫy nằm ngay sau bài viết này</h2>

<p>Hiểu đúng về lạm phát sinh ra nỗi sợ, và nỗi sợ là thứ bị khai thác nhiều nhất.</p>

<p>Gần như mọi mô hình lừa đảo tài chính ở Việt Nam hai chục năm qua đều mở đầu bằng <strong>đúng</strong> những chẩn đoán ở trên — tiền mất giá, ngân hàng in tiền, gửi tiết kiệm là thua — rồi kết thúc bằng “gửi tiền vào đây, cam kết ba phần trăm một tháng”.</p>

<p><strong>Chẩn đoán đúng không làm cho giải pháp đi kèm trở nên đúng.</strong></p>

<p>Lạm phát 5% một năm là chuyện nghiêm trọng nhưng diễn ra chậm. Mất trắng vốn vì đòn bẩy hoặc vì lừa đảo thì nhanh và không hồi phục được. Đừng để cái chậm đẩy mình vào cái nhanh.</p>

<h2 id="bài-này-không-nói-gì">Bài này không nói gì</h2>

<p>Mình không phải người tư vấn tài chính và không có giấy phép hành nghề. Đây là ghi chép nghiên cứu của mình cùng lý do đằng sau lựa chọn của riêng mình, không phải khuyến nghị cho ai mua bán thứ gì.</p>

<p>Số liệu chốt ngày <strong>11/9/2026</strong> và lấy từ các nguồn liệt kê bên dưới. Riêng số liệu Việt Nam giai đoạn 1996–2003 có thể lệch 0,3 tới 0,5 điểm phần trăm giữa các bản công bố, vì rổ hàng đã thay đổi nhiều lần trong ba mươi năm.</p>

<p>Bitcoin đặc biệt không phải thứ nên chép lại tỷ lệ của người khác. Nó có thể giảm một nửa trong vài tháng, và nó chưa có đủ lịch sử để ai đó nói chắc chắn về nó như nói về cổ phiếu.</p>

<p>Chúc các bạn thành công.</p>

<h2 id="link-tham-khảo">Link tham khảo</h2>

<p><a href="https://www.usinflationcalculator.com/inflation/historical-inflation-rates/">https://www.usinflationcalculator.com/inflation/historical-inflation-rates/</a></p>

<p><a href="https://baochinhphu.vn/cpi-nam-2025-tang-331-dat-muc-tieu-quoc-hoi-de-ra-102260105160120695.htm">https://baochinhphu.vn/cpi-nam-2025-tang-331-dat-muc-tieu-quoc-hoi-de-ra-102260105160120695.htm</a></p>

<p><a href="https://nief.mof.gov.vn/kinh-te-xa-hoi/toan-canh-thi-truong-vang-viet-nam-nam-2025-va-du-bao-nam-2026-11833.html">https://nief.mof.gov.vn/kinh-te-xa-hoi/toan-canh-thi-truong-vang-viet-nam-nam-2025-va-du-bao-nam-2026-11833.html</a></p>]]></content><author><name>Thành</name></author><category term="tai-chinh" /><category term="chia-se" /><category term="lạm phát" /><category term="CPI" /><category term="đầu tư" /><category term="tích sản" /><category term="BTC" /><category term="chứng khoán" /><summary type="html"><![CDATA[Ba mươi năm qua, tiền đồng mất **79,5% sức mua**, đô la Mỹ mất 52,6%. Số liệu chính thức không hề bị bịa — mình có kiểm chứng chéo. Nhưng cung tiền tăng **gấp 300 lần** trong khi rổ hàng CPI chỉ tăng 4,9 lần, và phần chênh đó chảy vào giá tài sản.]]></summary></entry><entry><title type="html">Mua vàng SJC là đặt hai cược cùng lúc, nên mình chọn PAXG</title><link href="https://sofsog.com/tai-chinh/mua-vang-sjc-dat-hai-cuoc-nen-minh-chon-paxg" rel="alternate" type="text/html" title="Mua vàng SJC là đặt hai cược cùng lúc, nên mình chọn PAXG" /><published>2026-09-11T00:00:00+00:00</published><updated>2026-09-11T00:00:00+00:00</updated><id>https://sofsog.com/tai-chinh/mua-vang-sjc-dat-hai-cuoc-nen-minh-chon-paxg</id><content type="html" xml:base="https://sofsog.com/tai-chinh/mua-vang-sjc-dat-hai-cuoc-nen-minh-chon-paxg"><![CDATA[<p>Khi mua một lượng vàng SJC, bạn đang đặt hai cược cùng lúc mà thường chỉ nghĩ mình đặt một.</p>

<p>Cược thứ nhất là giá vàng thế giới. Cược thứ hai là khoảng chênh giữa giá trong nước và giá thế giới — thứ không ai dự đoán được và không liên quan gì tới vàng.</p>

<aside class="series-box" aria-label="Các bài trong series Đầu tư dài hạn"><p class="series-box__dau">Series <a href="/series/">Đầu tư dài hạn</a> &middot; bài 4/4 <span class="series-box__cap">Cơ bản</span></p><ol class="series-box__ds"><li><a href="/tai-chinh/lam-phat-30-nam-tien-mat-gia-la-thiet-ke">Lạm phát 30 năm: tiền mất giá là thiết kế, nên mình mua tài sản dần</a></li><li><a href="/tai-chinh/bot-vang-thang-lai-20-phan-tram-roi-tai-khoan-ve-0">Bot vàng của mình có tháng lãi 20%, rồi tài khoản về 0</a></li><li><a href="/tai-chinh/danh-muc-dai-han-83-phan-tram-van-nam-o-tien-mat">Danh mục dài hạn của mình: 83% vẫn đang nằm ở tiền mặt</a></li><li class="dang-doc" aria-current="true">Mua vàng SJC là đặt hai cược cùng lúc, nên mình chọn PAXG</li></ol></aside>

<p><a href="/tai-chinh/danh-muc-dai-han-83-phan-tram-van-nam-o-tien-mat">Bài trước</a> mình có nói danh mục dành 10% cho vàng. Bài này là lý do mình chọn PAXG cho phần đó thay vì vàng miếng, và quan trọng không kém, những thứ PAXG <strong>không</strong> làm được.</p>

<h2 id="con-số-làm-mình-quyết-định">Con số làm mình quyết định</h2>

<p><img src="/assets/images/2026/2026-09-11-paxg-vang-token-sofsog.com01.png" alt="Hình biểu đồ chênh lệch giá vàng SJC so với giá thế giới trong năm 2026 sofsog.com" /></p>

<p>Cùng một năm 2026, khoảng chênh đi từ <strong>2 triệu</strong> lên <strong>hơn 28 triệu</strong> rồi về lại quanh 10 triệu.</p>

<p>Hãy hình dung hai người cùng tin vàng sẽ lên. Người mua đúng lúc chênh 28 triệu và người mua lúc chênh 2 triệu cầm cùng một thứ kim loại, nhưng người thứ nhất trả thêm 26 triệu mỗi lượng cho một thứ không phải vàng. Nếu sau đó giá thế giới đi ngang mà khoảng chênh co lại, người thứ nhất lỗ trong khi vàng chẳng mất giá đồng nào.</p>

<p>Cách tính khoảng chênh cũng đơn giản, ai cũng tự làm được. Một lượng là 37,5 gam, tức <strong>1,20565 troy ounce</strong>. Lấy giá vàng thế giới nhân với con số đó rồi nhân tỷ giá đô la bán ra:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>4.317 USD/oz × 1,20565 × 26.100 ≈ 135,8 triệu đồng/lượng
</code></pre></div></div>

<p>Hôm nay SJC bán ra 146,6 triệu. Chênh khoảng <strong>10,8 triệu một lượng, tầm 8%</strong>.</p>

<p>Khoảng chênh đó thực chất là <strong>rủi ro chính sách được đội vào giá vàng</strong>: nó phụ thuộc hạn mức nhập khẩu, nguồn cung trong nước, và tâm lý xếp hàng mua vàng. Mình muốn mua vàng, không muốn mua thêm cái đó.</p>

<h2 id="paxg-thật-ra-là-cái-gì">PAXG thật ra là cái gì</h2>

<p>Nói cho gọn: <strong>một PAXG tương ứng một troy ounce vàng thật</strong>, loại thanh London Good Delivery, đang nằm trong kho Brink’s và Malca-Amit ở London theo chuẩn LBMA. Thanh vàng có số serial tra được.</p>

<p>Đơn vị phát hành là Paxos Trust Company. Từ tháng 12 năm 2025, Paxos chuyển sang hoạt động dưới giấy phép national trust của <strong>OCC</strong>, cơ quan quản lý ngân hàng liên bang Mỹ. Vàng được kiểm chứng bằng <strong>báo cáo attestation hàng tháng do KPMG</strong> thực hiện.</p>

<p>Quy mô hiện tại khoảng 433.300 PAXG, tức <strong>13,5 tấn vàng</strong>, vốn hoá chừng 2 tỷ đô.</p>

<p>Một điểm về cấu trúc pháp lý đáng để ý: Paxos công bố vàng được giữ dưới dạng tài sản của khách hàng, <strong>tách khỏi bảng cân đối kế toán của Paxos</strong>. Nếu Paxos mất khả năng thanh toán thì về nguyên tắc số vàng đó không nằm trong khối tài sản đem chia cho chủ nợ. Đây là khác biệt thật so với việc gửi vàng cho một sàn giao dịch rồi cầm một con số trong hệ thống của họ.</p>

<p>Nhưng đừng nhầm nó với tài sản phi tập trung. Mình sẽ nói ngay bên dưới.</p>

<h2 id="chi-phí-0205-so-với-2">Chi phí: 0,2–0,5% so với 2%</h2>

<p>Đây là phần hợp với người tích sản đều đặn hằng tháng nhất.</p>

<p><strong>Phí lưu ký PAXG là 0.</strong> Không phải thấp — là không có. Để so sánh, quỹ ETF vàng quốc tế GLD thu khoảng 0,4% mỗi năm, còn thuê két ngân hàng ở Việt Nam tốn một tới ba triệu một năm.</p>

<p>Mua bán trên sàn mất khoảng 0,1% mỗi chiều. <strong>Tổng chi phí một vòng mua rồi bán rơi vào 0,2–0,5%.</strong></p>

<p>Còn vàng miếng: hôm nay SJC mua vào 143,6 triệu, bán ra 146,6 triệu. Vừa mua xong là đã <strong>âm khoảng 2,05%</strong>. Vàng nhẫn còn rộng hơn, 2 tới 4%.</p>

<p>Chênh bốn tới mười lần. Với người mua một lần rồi cất hai chục năm thì khoản này không đáng kể. Với người <strong>bỏ vài triệu mỗi tháng đều đặn</strong> thì nó cộng dồn thành con số thật.</p>

<p>Thêm một điểm thực dụng: PAXG mua được vài trăm nghìn đồng một lần và chia nhỏ tới mười tám chữ số thập phân. Vàng vật chất phải chờ gom đủ tiền mua một chỉ hoặc một lượng, và chịu spread mỗi lần mua.</p>

<p>Còn một chuyện nhỏ nhưng dễ quên: nhiều bài hướng dẫn trên mạng nêu các con số như “phí huỷ token 15.000 đô một lần” hay “phí vận chuyển 2.500–8.000 đô”. Mình tra biểu phí Paxos công bố thì <strong>không có những khoản đó</strong> — Paxos chỉ công bố bậc thang 0,03% tới 1% cho việc tạo và huỷ token qua tài khoản của họ. Đừng lập kế hoạch dựa trên số liệu của mấy trang viết cho máy tìm kiếm đọc.</p>

<h2 id="ba-thứ-paxg-không-làm-được">Ba thứ PAXG không làm được</h2>

<p>Phần này quan trọng hơn phần khen bên trên, và nó là lý do mình không khuyên ai bỏ vàng miếng.</p>

<p><strong>Một: bạn ở Việt Nam thì gần như không đổi được ra vàng cầm tay.</strong> Muốn nhận một thanh Good Delivery từ Paxos thì cần tối thiểu 430 PAXG, tức khoảng 1,85 triệu đô, và Paxos chỉ giao vào kho LBMA trên lãnh thổ Anh chứ không giao tới nhà. Có đường đổi lẻ qua đối tác Alpha Bullion với thanh 1 gam tới 1 kg và không có mức tối thiểu, nhưng họ <strong>chỉ giao trong Mỹ và Canada</strong>.</p>

<p>Nên câu quảng cáo “đổi ra vàng thật được nên an toàn như vàng vật chất” là câu nghe hay mà không dùng được. Với người ở đây, PAXG là công cụ <strong>nắm giá vàng và thanh lý ra tiền</strong>, không phải con đường để có vàng nằm trong tay.</p>

<p><strong>Hai: pháp lý Việt Nam còn là vùng xám.</strong> Luật Công nghiệp công nghệ số có hiệu lực từ 1/1/2026 lần đầu công nhận tài sản mã hoá là tài sản để đầu tư — nhưng dùng nó để thanh toán hàng hoá dịch vụ vẫn là vi phạm. Theo cơ chế thí điểm, giao dịch chỉ hợp lệ khi qua sàn được cấp phép, mà <strong>tới tháng 9/2026 vẫn chưa sàn nào được cấp phép</strong>; mới có năm hồ sơ qua sơ tuyển. Mua qua sàn quốc tế hay qua P2P hiện vẫn nằm ngoài khung đó. Mua vàng SJC thì minh bạch hoàn toàn, không phải nghĩ.</p>

<p>Rủi ro thực tế hay xảy ra hơn cả chuyện Paxos sụp đổ là <strong>nhận tiền P2P từ nguồn dính hoạt động phạm pháp rồi bị phong toả tài khoản ngân hàng</strong>.</p>

<p><strong>Ba: PAXG không phải tài sản phi tập trung.</strong> Mã nguồn hợp đồng mở trên GitHub, và đọc kỹ thì thấy Paxos giữ những quyền này: đóng băng số dư của một địa chỉ, <strong>xoá số dư của địa chỉ đã đóng băng</strong> để phục vụ tịch thu, nâng cấp logic hợp đồng mà giữ nguyên địa chỉ, tạm dừng toàn bộ giao dịch, và bật lại phí chuyển on-chain — mức phí này từng đặt 0,02% mỗi lần chuyển, hiện để 0 nhưng cơ chế vẫn còn nguyên trong mã.</p>

<p>Paxos nói đây là yêu cầu của cơ quan quản lý và chỉ thực hiện theo lệnh toà. Mình tin điều đó hợp lý. Nhưng phải gọi đúng tên: <strong>PAXG là chứng thư sở hữu vàng được số hoá, do một tổ chức tập trung kiểm soát.</strong> Vừa là ưu điểm vì có người chịu trách nhiệm và có kiểm toán, vừa là nhược điểm vì có người chặn được bạn.</p>

<h2 id="rủi-ro-lớn-nhất-là-chính-mình">Rủi ro lớn nhất là chính mình</h2>

<p>Nếu chỉ được nhớ một câu trong bài này thì nên nhớ câu này.</p>

<p>Mất coin vì mất seed phrase, vì dính phishing, vì gửi nhầm địa chỉ — đó là rủi ro số một xét về mặt thống kê, cao hơn hẳn khả năng Paxos sụp hay kho vàng có chuyện. Vàng trong két thì còn có trộm, cháy, thất lạc, nhưng ít nhất bạn không thể xoá sổ nó bằng một cú dán nhầm.</p>

<p>Nói “an toàn hơn vì không sợ trộm” là nói sai. Nó không bỏ rủi ro đi, nó <strong>đổi rủi ro trộm lấy rủi ro tự mình làm hỏng</strong>.</p>

<p>Nếu giữ PAXG thì những việc sau là bắt buộc chứ không phải tuỳ chọn: để trên ví cứng chứ không để trên sàn, ghi seed phrase lên tấm kim loại và cất hai nơi, chuyển thử một khoản nhỏ trước khi chuyển khoản lớn, và mỗi tháng vào trang minh bạch của Paxos xem báo cáo KPMG mới nhất.</p>

<h2 id="khi-nào-vàng-miếng-đúng-hơn">Khi nào vàng miếng đúng hơn</h2>

<p>Vàng miếng không thua. Nó làm một việc khác.</p>

<p>Mua vàng vật chất khi mục tiêu là <strong>nắm kim loại</strong>: phòng rủi ro hệ thống thật sự, của để dành truyền đời, chuyện cưới hỏi, hoặc đơn giản là muốn chắc chắn về pháp lý và không muốn dính tới ví với seed phrase. PAXG cần có điện, có internet, có blockchain, và có tổ chức phát hành còn sống — nếu bạn mua vàng đúng để phòng cái ngày những thứ đó không còn thì PAXG không phục vụ mục đích ấy.</p>

<p>Có một thay đổi đáng theo dõi: <strong>Nghị định 232/2025/NĐ-CP</strong>, hiệu lực từ 10/10/2025, đã xoá độc quyền nhà nước về sản xuất vàng miếng và cho phép doanh nghiệp cùng ngân hàng đủ điều kiện được sản xuất, nhập khẩu theo hạn mức. Nguồn cung tăng thì về dài hạn khoảng chênh có xu hướng thu hẹp. Tức là <strong>lợi thế lớn nhất của PAXG sẽ mỏng dần đi</strong>, chứ không mất hẳn.</p>

<p>Về thuế thì hai bên giờ gần như bằng nhau: vàng miếng chịu thuế thu nhập cá nhân 0,1% khi chuyển nhượng từ 1/7/2026, còn tài sản mã hoá chịu 0,1% trên mỗi lần chuyển nhượng từ 27/3/2026. Thuế không còn là lý do để chọn bên nào. Chỉ lưu ý 0,1% của tài sản mã hoá tính <strong>trên từng lần giao dịch và không trừ lỗ</strong>, nên giao dịch càng nhiều càng bào mòn — thêm một lý do để mua và giữ thay vì lướt.</p>

<h2 id="vì-sao-mình-vẫn-chọn-paxg-cho-phần-vàng">Vì sao mình vẫn chọn PAXG cho phần vàng</h2>

<p>Gộp lại thì quyết định của mình dựa trên đúng ba điều.</p>

<p>Phần vàng trong danh mục của mình có nhiệm vụ <strong>bám theo giá vàng thế giới</strong>, không phải để cất trong két phòng ngày tận thế. Mình mua <strong>đều đặn từng khoản nhỏ hằng tháng</strong>, nên chênh lệch chi phí bốn tới mười lần là khoản cộng dồn thật. Và mình không muốn phần tài sản phòng thủ của mình lại gánh thêm một rủi ro chính sách nội địa dao động từ 2 tới 28 triệu một lượng.</p>

<p>Đổi lại, mình chấp nhận đủ cả: vùng xám pháp lý, rủi ro tổ chức phát hành, khả năng bị đóng băng theo lệnh toà Mỹ, thanh khoản mỏng hơn vàng thật, thêm một lớp rủi ro tỷ giá đô la trên đường về tiền đồng, và trách nhiệm tự giữ khoá.</p>

<p>Đây là lựa chọn phù hợp với mục tiêu của mình, không phải kết luận rằng PAXG tốt hơn vàng miếng. Hai thứ làm hai việc khác nhau. <strong>PAXG nắm giá vàng. Vàng miếng nắm kim loại.</strong> Ai lẫn lộn hai mục đích đó sẽ chọn sai, dù chọn bên nào.</p>

<h2 id="bài-này-không-nói-gì">Bài này không nói gì</h2>

<p>Mình không phải người tư vấn tài chính và không có giấy phép hành nghề. Đây là ghi chép nghiên cứu của mình cùng lý do đằng sau một quyết định của riêng mình, không phải khuyến nghị cho ai mua hay bán thứ gì.</p>

<p>Mọi số liệu trong bài chốt ngày <strong>11/9/2026</strong> — giá vàng, tỷ giá, mức chênh lệch và tình trạng cấp phép đều đổi liên tục, nên hãy kiểm tra lại trước khi dựa vào chúng. Phần quy định pháp luật mình dẫn theo văn bản và nguồn liệt kê bên dưới; ai định làm theo thì nên đọc thẳng văn bản gốc chứ đừng tin một bài blog.</p>

<p>Và xin nhắc lại điều quan trọng nhất: <strong>mua PAXG qua sàn quốc tế hoặc P2P ở thời điểm này vẫn nằm ngoài khung pháp lý đã được cấp phép tại Việt Nam.</strong> Mình viết ra vì mình chọn vậy và mình chấp nhận, không phải để rủ ai làm theo.</p>

<p>Chúc các bạn thành công.</p>

<h2 id="link-tham-khảo">Link tham khảo</h2>

<p><a href="https://www.paxos.com/pax-gold">https://www.paxos.com/pax-gold</a></p>

<p><a href="https://www.paxos.com/paxg-transparency">https://www.paxos.com/paxg-transparency</a></p>

<p><a href="https://github.com/paxosglobal/paxos-gold-contract">https://github.com/paxosglobal/paxos-gold-contract</a></p>

<p><a href="https://xaydungchinhsach.chinhphu.vn/toan-van-nghi-dinh-so-232-2025-nd-cp-sua-doi-bo-sung-nghi-dinh-24-2012-nd-cp-ve-quan-ly-hoat-dong-kinh-doanh-vang-119250829100240562.htm">https://xaydungchinhsach.chinhphu.vn/toan-van-nghi-dinh-so-232-2025-nd-cp-sua-doi-bo-sung-nghi-dinh-24-2012-nd-cp-ve-quan-ly-hoat-dong-kinh-doanh-vang-119250829100240562.htm</a></p>]]></content><author><name>Thành</name></author><category term="tai-chinh" /><category term="chia-se" /><category term="vàng" /><category term="PAXG" /><category term="SJC" /><category term="đầu tư" /><category term="tích sản" /><category term="DCA" /><summary type="html"><![CDATA[Trong năm 2026, chênh lệch giữa vàng SJC và giá thế giới đi từ **2 triệu tới hơn 28 triệu đồng một lượng**. Mua vàng miếng là cược vào cả giá vàng lẫn khoảng chênh đó. Bài này là lý do mình chọn **PAXG** cho phần vàng trong danh mục, và ba thứ nó không làm được.]]></summary></entry><entry><title type="html">Danh mục dài hạn của mình: 83% vẫn đang nằm ở tiền mặt</title><link href="https://sofsog.com/tai-chinh/danh-muc-dai-han-83-phan-tram-van-nam-o-tien-mat" rel="alternate" type="text/html" title="Danh mục dài hạn của mình: 83% vẫn đang nằm ở tiền mặt" /><published>2026-09-07T00:00:00+00:00</published><updated>2026-09-07T00:00:00+00:00</updated><id>https://sofsog.com/tai-chinh/danh-muc-dai-han-83-phan-tram-van-nam-o-tien-mat</id><content type="html" xml:base="https://sofsog.com/tai-chinh/danh-muc-dai-han-83-phan-tram-van-nam-o-tien-mat"><![CDATA[<p><a href="/tai-chinh/bot-vang-thang-lai-20-phan-tram-roi-tai-khoan-ve-0">Bài trước</a> mình kể vì sao bỏ hẳn bot giao dịch. Bài này là thứ thay thế nó.</p>

<p>Nhưng phải nói ngay một điều không đẹp: cái mình sắp cho bạn xem <strong>chưa phải một danh mục, mới là một kế hoạch đang làm dở</strong>.</p>

<aside class="series-box" aria-label="Các bài trong series Đầu tư dài hạn"><p class="series-box__dau">Series <a href="/series/">Đầu tư dài hạn</a> &middot; bài 3/4 <span class="series-box__cap">Cơ bản</span></p><ol class="series-box__ds"><li><a href="/tai-chinh/lam-phat-30-nam-tien-mat-gia-la-thiet-ke">Lạm phát 30 năm: tiền mất giá là thiết kế, nên mình mua tài sản dần</a></li><li><a href="/tai-chinh/bot-vang-thang-lai-20-phan-tram-roi-tai-khoan-ve-0">Bot vàng của mình có tháng lãi 20%, rồi tài khoản về 0</a></li><li class="dang-doc" aria-current="true">Danh mục dài hạn của mình: 83% vẫn đang nằm ở tiền mặt</li><li><a href="/tai-chinh/mua-vang-sjc-dat-hai-cuoc-nen-minh-chon-paxg">Mua vàng SJC là đặt hai cược cùng lúc, nên mình chọn PAXG</a></li></ol></aside>

<h2 id="hiện-trạng-và-mục-tiêu">Hiện trạng và mục tiêu</h2>

<p><img src="/assets/images/2026/2026-09-07-danh-muc-dai-han-sofsog.com01.png" alt="Hình biểu đồ so sánh tỷ lệ phân bổ tài sản hiện tại và mục tiêu sofsog.com" /></p>

<table>
  <thead>
    <tr>
      <th>Nhóm</th>
      <th>Đang có</th>
      <th>Mục tiêu</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Tiền mặt (stablecoin + tiền đồng)</td>
      <td><strong>83,65%</strong></td>
      <td>4%</td>
    </tr>
    <tr>
      <td>Crypto (Bitcoin + Ethereum)</td>
      <td>13,78%</td>
      <td>26%</td>
    </tr>
    <tr>
      <td>Vàng</td>
      <td>1,39%</td>
      <td>10%</td>
    </tr>
    <tr>
      <td>Cổ phiếu (ETF Mỹ + quỹ Việt Nam)</td>
      <td><strong>1,17%</strong></td>
      <td>60%</td>
    </tr>
  </tbody>
</table>

<p>Bốn khoản cổ phiếu của mình cộng lại chưa tới <strong>1,2%</strong> tổng tài sản. Phần lớn tiền vẫn nằm im.</p>

<p>Nói cách khác: mình có một bảng phân bổ đầy đủ, một mục tiêu rõ ràng, và gần như chưa thực hiện được gì.</p>

<h2 id="vì-sao-công-khai-lúc-còn-dở-dang">Vì sao công khai lúc còn dở dang</h2>

<p>Vì đó là lúc duy nhất còn trung thực được.</p>

<p>Gần như mọi bài viết về đầu tư mà bạn đọc đều viết từ vạch đích: người viết đã xong, đã lãi, rồi kể lại con đường như thể họ biết trước. Mình không ở vị trí đó và cũng không muốn giả vờ.</p>

<p>Còn một lý do thực tế hơn: viết ra thì mình khó lùi. Bảng phân bổ nằm trên blog công khai, mỗi quý mình sẽ cập nhật lại đúng bảng này. Ai đọc bài hôm nay có thể quay lại sau một năm và tự kiểm chứng mình có làm đúng thứ mình viết không.</p>

<h2 id="danh-mục-mục-tiêu-và-vai-trò-từng-khoản">Danh mục mục tiêu và vai trò từng khoản</h2>

<table>
  <thead>
    <tr>
      <th>Khoản</th>
      <th>Mục tiêu</th>
      <th>Vai trò</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Bitcoin</td>
      <td>24%</td>
      <td>Phần rủi ro cao nhất, cũng là phần kỳ vọng cao nhất</td>
    </tr>
    <tr>
      <td>Ethereum</td>
      <td>2%</td>
      <td>Giữ nhỏ, không phải trọng tâm</td>
    </tr>
    <tr>
      <td>Vàng (PAXG)</td>
      <td>10%</td>
      <td>Phòng thủ, chống mất giá tiền tệ</td>
    </tr>
    <tr>
      <td>QQQon</td>
      <td>20%</td>
      <td>Cổ phiếu công nghệ Mỹ</td>
    </tr>
    <tr>
      <td>SPYon</td>
      <td>20%</td>
      <td>500 công ty lớn nhất thị trường Mỹ</td>
    </tr>
    <tr>
      <td>Quỹ VESAF</td>
      <td>10%</td>
      <td>Cổ phiếu Việt Nam</td>
    </tr>
    <tr>
      <td>Quỹ DCDS</td>
      <td>10%</td>
      <td>Cổ phiếu Việt Nam</td>
    </tr>
    <tr>
      <td>Tiền mặt</td>
      <td>4%</td>
      <td>Xoay vòng, không phải để giữ</td>
    </tr>
  </tbody>
</table>

<p>Gộp lại: <strong>40% cổ phiếu Mỹ, 20% cổ phiếu Việt Nam, 26% crypto, 10% vàng, 4% tiền mặt.</strong></p>

<p>Hai quỹ Việt Nam nằm cạnh hai quỹ Mỹ là có chủ ý. Mình sống ở Việt Nam, tiêu bằng tiền đồng, nên giữ một phần tài sản gắn với nền kinh tế mình đang sống là hợp lý với mình. Nhưng chỉ một phần, vì nếu công việc, thu nhập và tài sản đều buộc vào cùng một nền kinh tế thì đó không còn là đa dạng hoá nữa.</p>

<h2 id="mục-tiêu-89-một-năm-và-bằng-đồng-tiền-nào">Mục tiêu 8–9% một năm, và bằng đồng tiền nào</h2>

<p>Đây là chỗ mình nghĩ nhiều nội dung tự do tài chính tiếng Việt bỏ sót, và cũng là chỗ nghề kế toán giúp mình.</p>

<p>Mục tiêu của mình là <strong>8–9% một năm, tính bằng đô la</strong>. Chữ “tính bằng đô la” không phải chi tiết phụ. Nó đổi hẳn bài toán.</p>

<p>Ví dụ ngay trên bàn: lãi suất gửi tiền đồng mình đang tiếp cận được là <strong>8,1% một năm</strong>. Nhìn qua thì gửi tiết kiệm đã gần đạt mục tiêu rồi, khỏi cần đầu tư gì cho mệt.</p>

<p>Nhưng 8,1% bằng tiền đồng và 8–9% bằng đô la không so trực tiếp với nhau được. Muốn so thì phải trừ đi phần tiền đồng mất giá so với đô la trong cùng kỳ. Giả sử mức đó là 3% một năm, thì 8,1% tiền đồng chỉ còn khoảng 5% tính theo đô. Giả sử là 1%, nó còn khoảng 7%. Mình không biết con số thật của những năm tới là bao nhiêu, và cũng không định đoán.</p>

<p>Điều mình muốn nói là: <strong>một con số lợi nhuận không kèm đơn vị tiền thì chưa nói lên điều gì.</strong> Mỗi lần thấy ai đó nói “kênh này lãi 12% một năm”, câu hỏi đầu tiên nên là mười hai phần trăm của đồng tiền nào.</p>

<p>Chiều ngược lại cũng đúng và mình phải tự nhắc: mình chi tiêu bằng tiền đồng. Đặt mục tiêu bằng đô nghĩa là tới lúc rút ra tiêu, mình vẫn phải đi qua tỷ giá một lần nữa.</p>

<h2 id="26-bitcoin-là-lựa-chọn-cá-nhân-không-phải-khuyến-nghị">26% Bitcoin là lựa chọn cá nhân, không phải khuyến nghị</h2>

<p>Tỷ lệ này chắc chắn cao hơn mức mà phần lớn hướng dẫn phân bổ tài sản khuyên. Mình biết, và mình vẫn để vậy, nhưng lý do thì phải nói cho đúng.</p>

<p>Mình để 24% cho Bitcoin <strong>vì cá nhân mình tin nó hơn các tài sản khác, và vì mình đã nắm giữ nó nhiều năm rồi.</strong> Đó là lý do mang tính cá nhân, không phải kết luận rút ra từ mô hình nào cả.</p>

<p>Nên nói thẳng: <strong>tỷ lệ này không dành cho người chưa từng nắm giữ Bitcoin và không tin vào nó.</strong> Cầm một tài sản có thể giảm một nửa trong vài tháng mà không bán tháo là chuyện của niềm tin và của kinh nghiệm đã trải, không phải chuyện đọc được trong một bài blog. Ai chưa qua chuyện đó mà bắt chước con số 24% thì nhiều khả năng sẽ bán đúng lúc không nên bán.</p>

<p>Đây cũng là phần duy nhất trong danh mục mà mình không thể ước lượng khoảng kết quả. Cổ phiếu Mỹ có hàng chục năm dữ liệu. Bitcoin thì không.</p>

<h2 id="qqqon-và-spyon-không-phải-là-qqq-và-spy">QQQon và SPYon không phải là QQQ và SPY</h2>

<p>Chỗ này mình muốn viết cho thật chính xác, vì bản thân mình cũng đã ghi sai trong bảng theo dõi của chính mình một thời gian.</p>

<p>Mình <strong>không sở hữu quỹ QQQ và SPY</strong>. Thứ mình nắm là <strong>QQQon và SPYon</strong> — bản mã hoá của hai quỹ đó, do Ondo Finance phát hành, chạy trên chuỗi khối. Mỗi token đại diện cho <strong>giá trị kinh tế</strong> của quỹ gốc, chứ không phải là một chứng chỉ quỹ đứng tên mình ở một công ty chứng khoán Mỹ.</p>

<p>Cái được: từ Việt Nam tiếp cận được hai quỹ lớn nhất thị trường Mỹ mà không cần mở tài khoản chứng khoán nước ngoài, giao dịch 24/7, và mua bán bằng tài sản số sẵn có.</p>

<p>Cái mất, và phải nói rõ: <strong>rủi ro không biến mất, nó đổi hình dạng.</strong> Thay vì rủi ro của một công ty chứng khoán được quản lý và có cơ chế bảo vệ nhà đầu tư, giờ là rủi ro của tổ chức phát hành cộng với rủi ro hợp đồng thông minh. Khả năng quy đổi ra tiền phụ thuộc vào tổ chức phát hành đó tiếp tục vận hành bình thường.</p>

<p>Ai định đi đường này thì nên đọc thẳng tài liệu của bên phát hành về điều kiện quy đổi trước, đừng đọc mỗi bài của mình.</p>

<p>Còn một câu mình chưa trả lời được: <strong>thuế</strong>. Mình là kế toán, và mình vẫn chưa có câu trả lời sạch sẽ cho việc kê khai thu nhập từ loại tài sản này ở Việt Nam. Mình đang tra và sẽ viết riêng một bài khi nào chắc chắn. Chưa chắc thì mình chưa viết, chứ không đoán bừa cho có bài.</p>

<h2 id="chỗ-sai-lớn-nhất-hiện-tại">Chỗ sai lớn nhất hiện tại</h2>

<p>Quay lại con số 83,65%.</p>

<p>Phần lớn tài sản của mình đang nằm ở <strong>stablecoin</strong>, và mình biết rõ đó là chỗ không nên để. Nói cho đủ thì nó tệ theo hai tầng.</p>

<p>Tầng thứ nhất: stablecoin không phải tiền gửi ngân hàng. Nó là <strong>quyền đòi nợ với tổ chức phát hành</strong>, và nó chỉ đáng giá đúng bằng mức tin cậy của tổ chức đó cùng tài sản bảo chứng phía sau.</p>

<p>Tầng thứ hai, nặng hơn: nếu để trên sàn giao dịch thì bạn còn không nắm giữ trực tiếp. Bạn nắm một con số trong hệ thống của sàn.</p>

<p>Mình đang chuyển dần ra: sang Bitcoin, sang hai quỹ trong nước, sang QQQon và SPYon, sang vàng, và một phần sang gửi tiền đồng lấy lãi suất 8,1% nêu ở trên.</p>

<p><strong>Chuyển dần chứ không chuyển một lần</strong>, và đây là chỗ bài này nối lại với bài trước. Mình không biết hôm nay là điểm cao hay điểm thấp của bất kỳ tài sản nào trong danh mục. Bài học đắt nhất mình có là mình không đoán được. Nên mình mua đều theo lịch và chấp nhận rằng có những lần mua trúng giá cao.</p>

<h2 id="kết-quả-tới-giờ-kể-cả-phần-đang-lỗ">Kết quả tới giờ, kể cả phần đang lỗ</h2>

<table>
  <thead>
    <tr>
      <th>Khoản</th>
      <th>Lãi/lỗ</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Bitcoin</td>
      <td><strong>+16,2%</strong></td>
    </tr>
    <tr>
      <td>Ethereum</td>
      <td>+9,6%</td>
    </tr>
    <tr>
      <td>QQQon</td>
      <td>+8,7%</td>
    </tr>
    <tr>
      <td>SPYon</td>
      <td>+8,2%</td>
    </tr>
    <tr>
      <td>Vàng (PAXG)</td>
      <td>−2,4%</td>
    </tr>
    <tr>
      <td>Quỹ VESAF</td>
      <td>khoảng −4%</td>
    </tr>
    <tr>
      <td>Quỹ DCDS</td>
      <td>−7,5%</td>
    </tr>
  </tbody>
</table>

<p>Ba khoản đang âm, và hai trong ba là quỹ cổ phiếu Việt Nam.</p>

<p>Quan trọng hơn: <strong>gần như toàn bộ phần lãi hiện nay đến từ đúng một khoản là Bitcoin.</strong> Nếu mình đăng bảng này vào lúc Bitcoin đang lên thì trông rất giỏi; nếu nó quay đầu thì bảng đổi màu gần hết. Đó chính là lý do vì sao con số của vài tháng không chứng minh được điều gì cả — kể cả khi nó xanh.</p>

<p>Mình đăng cả phần âm vì một bảng chỉ toàn số dương là một bảng đã được chọn lọc.</p>

<h2 id="những-gì-mình-không-làm">Những gì mình không làm</h2>

<p>Không đòn bẩy. Không đoán điểm mua điểm bán. Không có cái máy nào phải bật hai mươi tư trên hai mươi tư. Không đổi tỷ lệ mục tiêu theo tin tức.</p>

<p>Việc duy nhất còn lại là mua đều và cân bằng lại khi tỷ lệ lệch quá xa. Nhàm chán, và đó là chủ đích.</p>

<h2 id="bài-này-không-nói-gì">Bài này không nói gì</h2>

<p>Mình không phải người tư vấn tài chính và không có giấy phép hành nghề. Đây là danh mục của mình cùng lý do đằng sau nó, không phải khuyến nghị cho ai mua hay bán thứ gì.</p>

<p>Tỷ lệ phù hợp với một người phụ thuộc vào tuổi, thu nhập, nghĩa vụ tài chính và mức chịu đựng rủi ro của chính người đó — bốn thứ mình không biết gì về bạn. Con số 24% Bitcoin của mình đặc biệt không nên chép lại.</p>

<p>Và một điều cuối: mọi con số lãi trong bài mới chỉ là vài tháng. Kế hoạch này tính bằng chục năm. Hẹn bạn ở bản cập nhật quý sau.</p>

<p>Chúc các bạn thành công.</p>]]></content><author><name>Thành</name></author><category term="tai-chinh" /><category term="chia-se" /><category term="đầu tư" /><category term="danh mục" /><category term="Bitcoin" /><category term="ETF" /><category term="chứng chỉ quỹ" /><category term="DCA" /><summary type="html"><![CDATA[Mục tiêu của mình là **8–9% một năm tính bằng đô**, dài hạn, để đi tới tự do tài chính. Đây là danh mục mục tiêu, vai trò từng khoản, và hiện trạng khó nói: **83,65% tài sản vẫn đang nằm ở tiền mặt** trong khi kế hoạch chỉ để 4%.]]></summary></entry><entry><title type="html">Bảo mật VPS Ubuntu: 36.802 lần bị dò mật khẩu trong 4 ngày</title><link href="https://sofsog.com/server/bao-mat-vps-ubuntu-36802-lan-do-mat-khau" rel="alternate" type="text/html" title="Bảo mật VPS Ubuntu: 36.802 lần bị dò mật khẩu trong 4 ngày" /><published>2026-09-05T00:00:00+00:00</published><updated>2026-09-05T00:00:00+00:00</updated><id>https://sofsog.com/server/bao-mat-vps-ubuntu-36802-lan-do-mat-khau</id><content type="html" xml:base="https://sofsog.com/server/bao-mat-vps-ubuntu-36802-lan-do-mat-khau"><![CDATA[<p>Cuối năm 2023 mình viết <a href="/thu-thuat-chung/he-dieu-hanh/ubuntu/huong-dan-tao-vps-tren-vultr-chi-tiet-nhat">bài hướng dẫn tạo VPS trên Vultr</a>. Bài đó dừng lại đúng chỗ nguy hiểm nhất: nó chỉ người đọc mở đăng nhập root qua SSH, rồi hết bài.</p>

<p>Hôm nay mình mở log của chính con VPS dựng theo hướng dẫn đó ra xem.</p>

<p><img src="/assets/images/2026/2026-09-05-bao-mat-vps-sofsog.com01.png" alt="Hình minh hoạ máy chủ VPS Ubuntu bị dò mật khẩu liên tục sofsog.com" /></p>

<h2 id="con-số-làm-mình-phải-viết-bài-này">Con số làm mình phải viết bài này</h2>

<p>Ubuntu ghi mọi lần đăng nhập thất bại vào <code class="language-plaintext highlighter-rouge">/var/log/btmp</code>. Đọc nó bằng lệnh <code class="language-plaintext highlighter-rouge">lastb</code>:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>lastb <span class="nt">-f</span> /var/log/btmp | <span class="nb">wc</span> <span class="nt">-l</span>
</code></pre></div></div>

<p>Máy mình trả về <strong>36.802</strong>. Tệp <code class="language-plaintext highlighter-rouge">btmp</code> được xoay vòng hằng tháng, tệp hiện tại bắt đầu lúc <code class="language-plaintext highlighter-rouge">2026-09-01 00:00:01</code>, nên đó là số lần trong <strong>bốn ngày chín tiếng</strong>. Trung bình khoảng 350 lần một giờ, tức là cứ mười giây lại có một lần gõ cửa.</p>

<p>Chúng đến từ 449 địa chỉ IP khác nhau:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>lastb | <span class="nb">grep</span> <span class="s2">"ssh:notty"</span> | <span class="nb">awk</span> <span class="s1">'{print $3}'</span> | <span class="nb">sort</span> <span class="nt">-u</span> | <span class="nb">wc</span> <span class="nt">-l</span>
</code></pre></div></div>

<p>Và đây là tên tài khoản chúng thử nhiều nhất:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  14943 root
   1692 admin
   1194 user
    704 ubuntu
    476 debian
    474 test
    414 deploy
    254 postgres
    252 ftpuser
</code></pre></div></div>

<p>Lệnh sinh ra bảng đó:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>lastb | <span class="nb">awk</span> <span class="s1">'{print $1}'</span> | <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span> | <span class="nb">sort</span> <span class="nt">-rn</span> | <span class="nb">head</span> <span class="nt">-12</span>
</code></pre></div></div>

<p>Nhìn danh sách này thì rõ một điều: <strong>gần một nửa số lần thử là nhắm vào <code class="language-plaintext highlighter-rouge">root</code></strong>. Đó không phải là ai đó ghét mình. Đó là các bot quét dải IP của mọi nhà cung cấp VPS, và <code class="language-plaintext highlighter-rouge">root</code> là cái tên duy nhất chắc chắn tồn tại trên mọi máy Linux. Cho phép đăng nhập root bằng mật khẩu qua SSH là tự tay bỏ đi một nửa bài toán của kẻ tấn công — chúng chỉ còn phải đoán mật khẩu.</p>

<p>Máy mình chưa bị chiếm. Nhưng “chưa bị” không phải là một chiến lược.</p>

<h2 id="kiểm-tra-máy-của-bạn-trước-đã">Kiểm tra máy của bạn trước đã</h2>

<p>Trước khi sửa gì, hãy xem máy bạn thật sự đang chạy với cấu hình nào. Đây là chỗ mình từng nhầm, và mình nghĩ nhiều người cũng nhầm.</p>

<p>Đừng đọc <code class="language-plaintext highlighter-rouge">/etc/ssh/sshd_config</code> rồi tin vào đó. Hãy hỏi thẳng OpenSSH:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>sshd <span class="nt">-T</span> | <span class="nb">grep</span> <span class="nt">-E</span> <span class="s1">'^port|permitrootlogin|passwordauthentication|pubkeyauthentication'</span>
</code></pre></div></div>

<p>Máy mình trả về:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>port 22
permitrootlogin yes
passwordauthentication yes
pubkeyauthentication yes
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">sshd -T</code> in ra <strong>giá trị đang thực sự có hiệu lực</strong> sau khi đã gộp hết mọi tệp cấu hình. Khác biệt giữa nó và nội dung tệp bạn vừa sửa là chỗ nhiều hướng dẫn trên mạng làm sai.</p>

<h3 id="cái-bẫy-thứ-tự-tệp-cấu-hình">Cái bẫy thứ tự tệp cấu hình</h3>

<p>Ubuntu từ bản 22.04 tách cấu hình SSH thành nhiều mảnh. Tệp chính <code class="language-plaintext highlighter-rouge">/etc/ssh/sshd_config</code> có một dòng gọi thư mục con vào:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Include /etc/ssh/sshd_config.d/*.conf
</code></pre></div></div>

<p>Quy tắc của OpenSSH là <strong>giá trị đọc được đầu tiên sẽ thắng</strong>, không phải giá trị cuối cùng. Đây là điều ngược với trực giác của gần như mọi người từng sửa tệp cấu hình.</p>

<p>Trên máy mình, dòng <code class="language-plaintext highlighter-rouge">Include</code> nằm ở <strong>dòng 15</strong>. Còn dòng <code class="language-plaintext highlighter-rouge">PermitRootLogin yes</code> — đúng cái dòng bài 2023 của mình bảo người đọc thêm vào — nằm ở <strong>dòng 2</strong>. Nó đứng trước, nên nó thắng tất cả. Bạn có tạo bao nhiêu tệp trong <code class="language-plaintext highlighter-rouge">sshd_config.d/</code> để tắt root cũng vô ích.</p>

<p>Ngược lại, <code class="language-plaintext highlighter-rouge">PasswordAuthentication</code> không hề xuất hiện trong tệp chính. Giá trị <code class="language-plaintext highlighter-rouge">yes</code> đang có hiệu lực đến từ một tệp do trình cài đặt của nhà cung cấp sinh ra:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cat</span> /etc/ssh/sshd_config.d/50-cloud-init.conf
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PasswordAuthentication yes
</code></pre></div></div>

<p>Hệ quả thực tế: một tệp drop-in đặt tên <code class="language-plaintext highlighter-rouge">99-hardening.conf</code> sẽ <strong>không</strong> sửa được gì, vì <code class="language-plaintext highlighter-rouge">99</code> sắp sau <code class="language-plaintext highlighter-rouge">50</code> theo thứ tự chữ cái, mà giá trị đầu tiên mới thắng. Muốn đè lên tệp cloud-init thì tệp của bạn phải sắp <strong>trước</strong> nó.</p>

<h2 id="việc-1-tắt-đăng-nhập-bằng-mật-khẩu">Việc 1: Tắt đăng nhập bằng mật khẩu</h2>

<p>Đây là việc quan trọng nhất trong bài. Làm xong việc này thì 36.802 lần thử kia trở thành tiếng ồn vô hại, vì không có mật khẩu nào để đoán nữa.</p>

<p>Điều kiện bắt buộc: <strong>bạn phải đăng nhập được bằng khoá SSH trước đã</strong>. Làm ngược thứ tự là tự khoá mình ở ngoài. Trên máy của bạn:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh-keygen <span class="nt">-t</span> ed25519 <span class="nt">-C</span> <span class="s2">"ten-may-cua-ban"</span>
ssh-copy-id root@dia-chi-vps
</code></pre></div></div>

<p>Rồi mở một cửa sổ terminal mới và thử đăng nhập. Nó phải vào thẳng, không hỏi mật khẩu. Kiểm tra khoá đã nằm đúng chỗ:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">grep</span> <span class="nt">-c</span> <span class="s2">"^ssh-"</span> ~/.ssh/authorized_keys
</code></pre></div></div>

<p>Máy mình trả về <code class="language-plaintext highlighter-rouge">7</code>. Con số đó hơi nhiều so với nhu cầu — mình sẽ nói ở cuối bài.</p>

<p>Vào được bằng khoá rồi thì tạo tệp drop-in, đặt tên bắt đầu bằng <code class="language-plaintext highlighter-rouge">10-</code> để nó sắp trước <code class="language-plaintext highlighter-rouge">50-cloud-init.conf</code>:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo tee</span> /etc/ssh/sshd_config.d/10-bao-mat.conf <span class="o">&gt;</span> /dev/null <span class="o">&lt;&lt;</span><span class="sh">'</span><span class="no">EOF</span><span class="sh">'
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
</span><span class="no">EOF
</span></code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">KbdInteractiveAuthentication</code> là con đường vòng: tắt mật khẩu mà quên tắt nó thì OpenSSH vẫn có thể hỏi mật khẩu qua cơ chế hỏi đáp của PAM.</p>

<p><strong>Đừng khởi động lại dịch vụ ngay.</strong> Kiểm tra cú pháp trước:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>sshd <span class="nt">-t</span>
</code></pre></div></div>

<p>Lệnh này không in gì nếu tệp cấu hình hợp lệ. Có lỗi thì nó chỉ đúng tệp và số dòng. Sai cú pháp mà cứ khởi động lại thì <code class="language-plaintext highlighter-rouge">sshd</code> không lên được, và cách duy nhất để cứu là vào bảng điều khiển noVNC của Vultr.</p>

<p>Hợp lệ rồi thì nạp lại cấu hình:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>systemctl reload ssh
</code></pre></div></div>

<p>Dùng <code class="language-plaintext highlighter-rouge">reload</code> chứ không phải <code class="language-plaintext highlighter-rouge">restart</code>: <code class="language-plaintext highlighter-rouge">reload</code> không cắt các phiên SSH đang mở. Nếu có gì sai, bạn vẫn còn cửa sổ hiện tại để sửa lại.</p>

<p>Xác minh:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>sshd <span class="nt">-T</span> | <span class="nb">grep </span>passwordauthentication
</code></pre></div></div>

<p>Phải ra <code class="language-plaintext highlighter-rouge">passwordauthentication no</code>.</p>

<p>Và <strong>mở một cửa sổ terminal thứ hai để thử đăng nhập lại</strong>, trong khi cửa sổ cũ vẫn giữ nguyên. Đây là bước nhiều người bỏ qua. Vào được thì mới đóng cửa sổ cũ.</p>

<h2 id="việc-2-cấm-root-đăng-nhập-thẳng">Việc 2: Cấm root đăng nhập thẳng</h2>

<p>Vì <code class="language-plaintext highlighter-rouge">PermitRootLogin yes</code> nằm ở dòng 2 của tệp chính, tệp drop-in không đè được. Phải sửa thẳng tệp chính:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo sed</span> <span class="nt">-i</span> <span class="s1">'s/^PermitRootLogin yes/PermitRootLogin prohibit-password/'</span> /etc/ssh/sshd_config
<span class="nb">sudo </span>sshd <span class="nt">-t</span> <span class="o">&amp;&amp;</span> <span class="nb">sudo </span>systemctl reload ssh
<span class="nb">sudo </span>sshd <span class="nt">-T</span> | <span class="nb">grep </span>permitrootlogin
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">prohibit-password</code> cho phép root vào bằng khoá nhưng cấm bằng mật khẩu. Nó là mức mặc định của Ubuntu và là lựa chọn mình dùng, vì các script quản trị của mình đang chạy dưới root qua khoá.</p>

<p>Chặt hơn nữa là <code class="language-plaintext highlighter-rouge">PermitRootLogin no</code>, buộc mọi người vào bằng user thường rồi <code class="language-plaintext highlighter-rouge">sudo</code> lên. Đúng bài hơn về nguyên tắc. Nhưng nó chỉ có ý nghĩa thật khi bạn đã có sẵn một user thường vào được bằng khoá và có quyền <code class="language-plaintext highlighter-rouge">sudo</code> — chưa có mà đặt <code class="language-plaintext highlighter-rouge">no</code> là tự khoá mình ra ngoài.</p>

<p>Kiểm tra tài khoản nào trên máy còn đặt mật khẩu:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>passwd <span class="nt">-S</span> root
</code></pre></div></div>

<p>Chữ cái thứ hai trong kết quả là thứ cần nhìn: <code class="language-plaintext highlighter-rouge">P</code> nghĩa là tài khoản có mật khẩu dùng được, <code class="language-plaintext highlighter-rouge">L</code> là đã khoá, <code class="language-plaintext highlighter-rouge">NP</code> là không có mật khẩu. Máy mình ra <code class="language-plaintext highlighter-rouge">P</code> — root có mật khẩu, và trong bốn ngày qua có 14.943 lần người ta thử đoán đúng nó.</p>

<h2 id="việc-3-tường-lửa-chỉ-mở-đúng-cổng-cần">Việc 3: Tường lửa chỉ mở đúng cổng cần</h2>

<p>Ubuntu có sẵn <code class="language-plaintext highlighter-rouge">ufw</code>. Thứ tự lệnh ở đây quan trọng hơn bản thân các lệnh:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>ufw allow 22/tcp
<span class="nb">sudo </span>ufw default deny incoming
<span class="nb">sudo </span>ufw default allow outgoing
<span class="nb">sudo </span>ufw <span class="nb">enable</span>
</code></pre></div></div>

<p><strong>Câu <code class="language-plaintext highlighter-rouge">allow 22/tcp</code> phải chạy trước <code class="language-plaintext highlighter-rouge">enable</code>.</strong> Bật tường lửa với chính sách chặn hết mà chưa mở cổng SSH thì phiên của bạn rớt ngay lập tức, và lại phải vào noVNC.</p>

<p>Khi chạy <code class="language-plaintext highlighter-rouge">ufw enable</code> nó sẽ hỏi:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Command may disrupt existing ssh connections. Proceed with operation (y|n)?
</code></pre></div></div>

<p>Đã mở cổng 22 ở bước trên thì cứ <code class="language-plaintext highlighter-rouge">y</code>.</p>

<p>Xem kết quả:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>ufw status verbose
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW IN    Anywhere
22/tcp (v6)                ALLOW IN    Anywhere (v6)
</code></pre></div></div>

<p>Đúng một cổng mở, và mở cho cả IPv4 lẫn IPv6. Dòng <code class="language-plaintext highlighter-rouge">(v6)</code> đáng để ý: VPS Vultr có địa chỉ IPv6, và một tường lửa chỉ chặn IPv4 là một tường lửa có cửa sau.</p>

<p>Sau này cài thêm dịch vụ gì thì mở thêm cổng đó, mỗi lần một cổng, và ghi lại lý do. Cách chắc chắn nhất để một máy chủ trở nên hở là mở cổng lúc thử nghiệm rồi quên đóng.</p>

<p>Đổi cổng SSH sang một số lạ thì sao? Nó cắt được gần hết log rác, vì bot quét cổng 22 là chính. Mình không làm, vì nó không thêm bảo mật thật một khi đã tắt mật khẩu — nó chỉ làm log sạch hơn, đổi lại mọi công cụ và mọi người trong nhóm phải nhớ thêm một con số.</p>

<h2 id="việc-4-swapfile-cho-máy-4-gb">Việc 4: Swapfile cho máy 4 GB</h2>

<p>Việc này không liên quan tới bảo mật, nhưng nó là thứ thứ hai làm hỏng một VPS mới, sau việc bị chiếm. Máy hết RAM thì nhân Linux giết tiến trình ngốn nhiều nhất, thường đúng là thứ bạn đang chạy.</p>

<p>Máy mình có 2 nhân CPU, đĩa 75 GB, và bộ nhớ như sau:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>               total        used        free      shared  buff/cache   available
Mem:            3910        2213         352         0        1637        1696
Swap:           2399         323        2076
</code></pre></div></div>

<p>RAM còn trống chỉ 352 MB, nhưng cột <code class="language-plaintext highlighter-rouge">available</code> là 1.696 MB — phần lớn chỗ “đã dùng” là bộ đệm đĩa, nhân sẽ trả lại khi cần. <strong>Cột đáng nhìn là <code class="language-plaintext highlighter-rouge">available</code>, không phải <code class="language-plaintext highlighter-rouge">free</code>.</strong></p>

<p>Swap đang dùng 323 MB trên 2.399 MB. Có dùng, nhưng chưa sâu. Máy mình có sẵn swapfile 2,3 GB; nếu máy bạn chưa có thì tạo như sau:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>fallocate <span class="nt">-l</span> 2G /swapfile
<span class="nb">sudo chmod </span>600 /swapfile
<span class="nb">sudo </span>mkswap /swapfile
<span class="nb">sudo </span>swapon /swapfile
<span class="nb">echo</span> <span class="s1">'/swapfile swap swap defaults 0 0'</span> | <span class="nb">sudo tee</span> <span class="nt">-a</span> /etc/fstab
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">chmod 600</code> là bắt buộc. Swapfile chứa nội dung bộ nhớ đã bị đẩy ra đĩa, trong đó có thể có mật khẩu và khoá; để nó cho mọi user đọc được là hỏng. Dòng thêm vào <code class="language-plaintext highlighter-rouge">/etc/fstab</code> để swap tự bật lại sau khi khởi động.</p>

<p>Kiểm tra:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>swapon <span class="nt">--show</span>
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>NAME      TYPE SIZE   USED PRIO
/swapfile file 2.3G 323.7M   -2
</code></pre></div></div>

<p>Còn một tham số nữa nên chỉnh:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cat</span> /proc/sys/vm/swappiness
</code></pre></div></div>

<p>Mặc định của Ubuntu là <code class="language-plaintext highlighter-rouge">60</code>. Máy mình là <code class="language-plaintext highlighter-rouge">10</code>, đặt trong <code class="language-plaintext highlighter-rouge">/etc/sysctl.conf</code> dòng 65. Số này quyết định nhân sốt sắng đến mức nào trong việc đẩy dữ liệu ra swap: <code class="language-plaintext highlighter-rouge">60</code> nghĩa là nó đẩy khá sớm, <code class="language-plaintext highlighter-rouge">10</code> nghĩa là chỉ đẩy khi thật sự cần. Trên máy ảo có đĩa chậm hơn RAM rất nhiều, <code class="language-plaintext highlighter-rouge">10</code> cho cảm giác mượt hơn hẳn. Đặt cố định:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">echo</span> <span class="s1">'vm.swappiness=10'</span> | <span class="nb">sudo tee</span> <span class="nt">-a</span> /etc/sysctl.conf
<span class="nb">sudo </span>sysctl <span class="nt">-p</span>
</code></pre></div></div>

<p>Swap là lưới an toàn, không phải RAM giá rẻ. Máy phải dùng swap thường xuyên là máy cần thêm RAM.</p>

<h2 id="việc-5-bật-cập-nhật-bảo-mật-tự-động">Việc 5: Bật cập nhật bảo mật tự động</h2>

<p>Ubuntu Server cài sẵn <code class="language-plaintext highlighter-rouge">unattended-upgrades</code>, nhưng nên xác nhận nó đang bật:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cat</span> /etc/apt/apt.conf.d/20auto-upgrades
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
</code></pre></div></div>

<p>Hai dòng, cùng giá trị <code class="language-plaintext highlighter-rouge">1</code>, là đủ. Thiếu tệp này hoặc giá trị <code class="language-plaintext highlighter-rouge">0</code> thì bật bằng:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>dpkg-reconfigure <span class="nt">--priority</span><span class="o">=</span>low unattended-upgrades
</code></pre></div></div>

<p>Xem thử nó sẽ làm gì mà chưa cài gì cả:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>unattended-upgrades <span class="nt">--dry-run</span> <span class="nt">--debug</span>
</code></pre></div></div>

<p>Và đây là chỗ mình bị hớ. Cập nhật tự động <strong>cài</strong> gói mới, nhưng nó không khởi động lại máy. Với bản vá nhân Linux, không khởi động lại thì nhân cũ vẫn đang chạy — tức là bản vá chưa có tác dụng gì cả:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">uname</span> <span class="nt">-r</span>
<span class="nb">cat</span> /var/run/reboot-required.pkgs
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>6.8.0-137-generic
linux-image-6.8.0-138-generic
linux-base
linux-image-6.8.0-139-generic
linux-base
</code></pre></div></div>

<p>Máy mình đang chạy nhân <code class="language-plaintext highlighter-rouge">137</code> trong khi <code class="language-plaintext highlighter-rouge">138</code> và <code class="language-plaintext highlighter-rouge">139</code> đã cài xong từ lúc nào không rõ. Chậm hai phiên bản nhân, trên một máy mà mình vẫn đinh ninh là “đã bật cập nhật tự động rồi”.</p>

<p>Tệp <code class="language-plaintext highlighter-rouge">/var/run/reboot-required</code> tồn tại là dấu hiệu cần khởi động lại. Kiểm tra nhanh mỗi khi SSH vào:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">[</span> <span class="nt">-f</span> /var/run/reboot-required <span class="o">]</span> <span class="o">&amp;&amp;</span> <span class="nb">echo</span> <span class="s2">"CAN KHOI DONG LAI"</span>
</code></pre></div></div>

<p>Muốn máy tự khởi động lại vào giờ vắng thì sửa <code class="language-plaintext highlighter-rouge">/etc/apt/apt.conf.d/50unattended-upgrades</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "04:00";
</code></pre></div></div>

<p>Mình chưa bật cái này, vì máy đang chạy một dịch vụ mà mình muốn tự tay canh lúc nó khởi động lại. Đó là một lựa chọn có giá của nó: đổi lấy quyền kiểm soát bằng việc phải nhớ, và mình vừa chứng minh là mình quên.</p>

<h2 id="còn-fail2ban-thì-sao">Còn fail2ban thì sao</h2>

<p>Máy mình không cài <code class="language-plaintext highlighter-rouge">fail2ban</code>. Nói rõ để bạn không tưởng là mình bỏ sót.</p>

<p><code class="language-plaintext highlighter-rouge">fail2ban</code> đọc log, thấy một IP thất bại nhiều lần thì chặn IP đó một khoảng thời gian. Nó hữu ích thật, nhưng hãy nhìn đúng vị trí của nó: <strong>khi đã tắt đăng nhập bằng mật khẩu, 36.802 lần thử kia không còn cơ hội nào cả.</strong> Chúng chỉ tốn một ít CPU và làm log phình ra — tệp <code class="language-plaintext highlighter-rouge">auth.log</code> của mình đã 23 MB cho sáu ngày.</p>

<p>Nên <code class="language-plaintext highlighter-rouge">fail2ban</code> với mình là việc dọn dẹp, không phải việc bảo mật, và nó xếp sau năm việc trên. Ai muốn cài thì trên Ubuntu 24.04:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt <span class="nb">install </span>fail2ban
</code></pre></div></div>

<p>Cấu hình đặt trong <code class="language-plaintext highlighter-rouge">/etc/fail2ban/jail.local</code> chứ đừng sửa <code class="language-plaintext highlighter-rouge">jail.conf</code>, vì tệp đó bị ghi đè mỗi lần nâng cấp gói.</p>

<h2 id="tự-chấm-điểm-máy-mình">Tự chấm điểm máy mình</h2>

<p>Đây là hiện trạng con VPS của mình lúc viết bài, chưa sửa gì:</p>

<table>
  <thead>
    <tr>
      <th>Việc</th>
      <th>Trạng thái</th>
      <th>Mức nguy hiểm</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Tường lửa chỉ mở cổng 22</td>
      <td>Đã làm</td>
      <td>—</td>
    </tr>
    <tr>
      <td>Swapfile và <code class="language-plaintext highlighter-rouge">swappiness</code></td>
      <td>Đã làm</td>
      <td>—</td>
    </tr>
    <tr>
      <td>Cập nhật tự động đang bật</td>
      <td>Đã làm</td>
      <td>—</td>
    </tr>
    <tr>
      <td>Đăng nhập bằng mật khẩu</td>
      <td><strong>Vẫn bật</strong></td>
      <td>Cao</td>
    </tr>
    <tr>
      <td>Root đăng nhập thẳng, có mật khẩu</td>
      <td><strong>Vẫn bật</strong></td>
      <td>Cao</td>
    </tr>
    <tr>
      <td>Khởi động lại sau vá nhân</td>
      <td><strong>Chậm 2 phiên bản</strong></td>
      <td>Vừa</td>
    </tr>
    <tr>
      <td>7 khoá trong <code class="language-plaintext highlighter-rouge">authorized_keys</code></td>
      <td>Chưa rà lại</td>
      <td>Vừa</td>
    </tr>
  </tbody>
</table>

<p>Ba dòng đầu là những việc mình làm đúng ngay từ đầu và quên mất là mình đã làm. Bốn dòng dưới là những việc mình tưởng đã xong.</p>

<p>Cái mình thấy đáng nói nhất là dòng cuối. Bảy khoá công khai trong <code class="language-plaintext highlighter-rouge">authorized_keys</code>, tích tụ qua nhiều năm, mỗi lần mua máy mới lại thêm một cái. Mình không còn nhớ chắc từng khoá thuộc máy nào, và trong số đó gần như chắc chắn có khoá của máy mình đã bán hoặc cài lại từ lâu. Tắt mật khẩu xong thì <code class="language-plaintext highlighter-rouge">authorized_keys</code> trở thành cánh cửa duy nhất — mà mình lại chưa từng kiểm kê nó lần nào.</p>

<p>Rà bằng lệnh này, phần ghi chú cuối mỗi dòng khoá thường là tên máy lúc tạo:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">awk</span> <span class="s1">'{print $NF}'</span> ~/.ssh/authorized_keys
</code></pre></div></div>

<p>Khoá nào không nhận ra thì xoá. Xoá nhầm khoá của máy đang dùng thì phiên SSH hiện tại vẫn sống, nên hãy giữ nguyên cửa sổ đó cho tới khi thử đăng nhập lại thành công từ cửa sổ khác.</p>

<h2 id="cập-nhật-cùng-ngày-mình-đã-sửa-hai-dòng-đỏ">Cập nhật cùng ngày: mình đã sửa hai dòng đỏ</h2>

<p>Viết xong bài thì không còn lý do gì để bảng trên giữ hai dòng “Vẫn bật”. Mình làm đúng Việc 1 và Việc 2, và phần đáng kể lại nhất là cách tự bảo hiểm.</p>

<p>Trước khi đụng vào gì, sao lưu tệp cấu hình rồi cài một cái chốt tự phục hồi. Ý tưởng đơn giản: nếu sau năm phút mình không tạo được tệp đánh dấu <code class="language-plaintext highlighter-rouge">/root/.ssh_ok</code> — nghĩa là mình đã tự khoá mình ở ngoài — thì máy tự khôi phục cấu hình cũ:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cp</span> <span class="nt">-a</span> /etc/ssh/sshd_config /root/sshd_config.bak
<span class="nb">rm</span> <span class="nt">-f</span> /root/.ssh_ok
<span class="nb">nohup </span>bash <span class="nt">-c</span> <span class="s1">'sleep 300; [ -f /root/.ssh_ok ] || {   cp -a /root/sshd_config.bak /etc/ssh/sshd_config;   rm -f /etc/ssh/sshd_config.d/10-bao-mat.conf;   systemctl reload ssh; }'</span> <span class="o">&gt;</span>/dev/null 2&gt;&amp;1 &amp;
</code></pre></div></div>

<p>Sửa xong và xác minh vào được thì tháo chốt:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">touch</span> /root/.ssh_ok
</code></pre></div></div>

<p>Cái chốt này đã cứu mình thật, ngay trong lần chạy đầu. Một bước ở giữa bị hỏng, và đúng năm phút sau máy tự trả về nguyên trạng, không mất gì và không cần mình can thiệp. Nếu bạn chỉ lấy một thứ từ bài này, hãy lấy đoạn trên: <strong>mọi thay đổi cấu hình SSH từ xa đều nên có đường lùi tự động.</strong></p>

<p>Lần chạy thứ hai trót lọt. <code class="language-plaintext highlighter-rouge">sshd -T</code> sau khi nạp lại:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>permitrootlogin without-password
pubkeyauthentication yes
passwordauthentication no
kbdinteractiveauthentication no
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">without-password</code> là tên cũ của <code class="language-plaintext highlighter-rouge">prohibit-password</code>. OpenSSH in ra tên cũ, ý nghĩa y hệt.</p>

<p>Rồi tự tấn công máy mình để kiểm chứng, ép client chỉ được phép dùng mật khẩu:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh <span class="nt">-o</span> <span class="nv">PubkeyAuthentication</span><span class="o">=</span>no <span class="nt">-o</span> <span class="nv">PreferredAuthentications</span><span class="o">=</span>password root@dia-chi-vps
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root@dia-chi-vps: Permission denied (publickey).
</code></pre></div></div>

<p>Máy chỉ còn chào đúng một phương thức. Đừng bỏ bước này: <code class="language-plaintext highlighter-rouge">sshd -T</code> cho biết cấu hình <strong>nói</strong> gì, còn lệnh trên cho biết máy chủ <strong>làm</strong> gì. Hai thứ đó lệch nhau thường xuyên hơn bạn tưởng — cả bài này sinh ra từ một lần lệch như vậy.</p>

<p>Hai dòng còn lại trong bảng thì vẫn còn nguyên đó. Nhân vẫn chậm hai phiên bản vì mình chưa chọn được lúc khởi động lại, và bảy cái khoá vẫn chưa rà. Ghi ra đây để lần sau mở bài này còn thấy mình nợ cái gì.</p>

<h2 id="thứ-tự-nên-làm">Thứ tự nên làm</h2>

<p>Nếu bạn chỉ có mười lăm phút, làm theo đúng thứ tự này:</p>

<p>Đưa khoá SSH lên và <strong>xác minh vào được bằng khoá</strong>. Rồi tắt <code class="language-plaintext highlighter-rouge">PasswordAuthentication</code>. Rồi đặt <code class="language-plaintext highlighter-rouge">PermitRootLogin prohibit-password</code>. Ba việc đó xử lý gần hết rủi ro thực tế. Tường lửa và swapfile làm sau cũng được, còn <code class="language-plaintext highlighter-rouge">fail2ban</code> thì lúc nào rảnh.</p>

<p>Bài hướng dẫn năm 2023 của mình sai ở chỗ nó coi việc dựng được máy là xong. Dựng xong mới là lúc máy bắt đầu bị quét, và trong bốn ngày nó hứng 36.802 lần gõ cửa mà mình không hề biết cho tới hôm nay.</p>

<h2 id="nếu-bạn-chưa-có-vps-nào-để-thử">Nếu bạn chưa có VPS nào để thử</h2>

<p>Mọi lệnh trong bài chỉ có nghĩa khi bạn có một cái máy để gõ vào. Con VPS của mình đặt ở Singapore, và mình đã viết <a href="/thu-thuat-chung/he-dieu-hanh/ubuntu/huong-dan-tao-vps-tren-vultr-chi-tiet-nhat">hướng dẫn tạo VPS trên Vultr từng bước</a> từ năm 2023 — phần tạo máy trong đó vẫn dùng được, chỉ có đoạn cuối về SSH là mình đã đánh dấu bỏ và thay bằng bài này.</p>

<p>Đăng ký tại <a href="https://www.vultr.com/?ref=7392243">vultr.com</a>.</p>

<p><strong>Nói rõ: đó là liên kết giới thiệu của mình.</strong> Bạn đăng ký qua nó thì mình được hoa hồng, còn bạn nhận khoản tín dụng dùng thử theo chương trình Vultr đang áp dụng — mức tín dụng và điều kiện thay đổi theo từng thời điểm nên bạn xem trên trang của họ, mình không hứa con số nào. Không thích thì gõ thẳng <code class="language-plaintext highlighter-rouge">vultr.com</code> vào trình duyệt, năm việc ở trên không vì thế mà khác đi.</p>

<p>Chúc các bạn thành công.</p>

<h2 id="link-tham-khảo">Link tham khảo</h2>

<p><a href="https://man.openbsd.org/sshd_config">https://man.openbsd.org/sshd_config</a></p>

<p><a href="https://help.ubuntu.com/community/UFW">https://help.ubuntu.com/community/UFW</a></p>

<p><a href="https://wiki.debian.org/UnattendedUpgrades">https://wiki.debian.org/UnattendedUpgrades</a></p>]]></content><author><name>Thành</name></author><category term="server" /><category term="ubuntu" /><category term="VPS" /><category term="Vultr" /><category term="Ubuntu" /><category term="SSH" /><category term="ufw" /><category term="bao-mat" /><summary type="html"><![CDATA[Cuối năm 2023 mình viết bài hướng dẫn tạo VPS trên Vultr, và bài đó bảo người đọc đặt **`PermitRootLogin yes`** rồi kết thúc. Hôm nay mình mở log của chính con VPS dựng theo hướng dẫn đó: **36.802 lần đăng nhập thất bại trong bốn ngày**, từ 449 địa chỉ IP. Đây là phần mình đã viết thiếu.]]></summary></entry><entry><title type="html">Bot vàng của mình có tháng lãi 20%, rồi tài khoản về 0</title><link href="https://sofsog.com/tai-chinh/bot-vang-thang-lai-20-phan-tram-roi-tai-khoan-ve-0" rel="alternate" type="text/html" title="Bot vàng của mình có tháng lãi 20%, rồi tài khoản về 0" /><published>2026-09-05T00:00:00+00:00</published><updated>2026-09-05T00:00:00+00:00</updated><id>https://sofsog.com/tai-chinh/bot-vang-thang-lai-20-phan-tram-roi-tai-khoan-ve-0</id><content type="html" xml:base="https://sofsog.com/tai-chinh/bot-vang-thang-lai-20-phan-tram-roi-tai-khoan-ve-0"><![CDATA[<p>Mình nghiên cứu một con bot giao dịch vàng trong nhiều năm. Có tháng nó lãi 20,44%. Có năm nó lãi 42,13%.</p>

<p>Rồi một tài khoản đi từ 237,90 đô xuống còn 13,39 đô, và sau đó về 0.</p>

<aside class="series-box" aria-label="Các bài trong series Đầu tư dài hạn"><p class="series-box__dau">Series <a href="/series/">Đầu tư dài hạn</a> &middot; bài 2/4 <span class="series-box__cap">Cơ bản</span></p><ol class="series-box__ds"><li><a href="/tai-chinh/lam-phat-30-nam-tien-mat-gia-la-thiet-ke">Lạm phát 30 năm: tiền mất giá là thiết kế, nên mình mua tài sản dần</a></li><li class="dang-doc" aria-current="true">Bot vàng của mình có tháng lãi 20%, rồi tài khoản về 0</li><li><a href="/tai-chinh/danh-muc-dai-han-83-phan-tram-van-nam-o-tien-mat">Danh mục dài hạn của mình: 83% vẫn đang nằm ở tiền mặt</a></li><li><a href="/tai-chinh/mua-vang-sjc-dat-hai-cuoc-nen-minh-chon-paxg">Mua vàng SJC là đặt hai cược cùng lúc, nên mình chọn PAXG</a></li></ol></aside>

<p>Bài này không hướng dẫn bạn chạy bot. Nó là bảng tính mình còn giữ được, con số thật của bốn tài khoản trong ba năm, và lý do vì sao bây giờ mình làm một việc chán hơn nhiều.</p>

<h2 id="bốn-tài-khoản-một-bảng-tính">Bốn tài khoản, một bảng tính</h2>

<p>Mình chạy EA — chương trình tự động giao dịch — trên cặp vàng, khung 5 phút, qua nhiều tài khoản song song ở các sàn khác nhau. Mỗi tháng mình ghi lại tỷ suất, số dư, và số tiền rút ra. Bảng tính đó mình vẫn còn.</p>

<p>Tài khoản đầu tiên mở tháng 10 năm 2022 với <strong>1.000 đô</strong>. Ba tháng cuối năm đó lãi lần lượt 0,17%, 12,6% và 10,3%, khép lại năm 2022 ở mức <strong>+24,41%</strong>.</p>

<p>Năm 2023 của tài khoản đó, từng tháng một:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Thg 1   +0,49%      Thg 7   +6,34%
Thg 2   +1,16%      Thg 8   +2,44%
Thg 3  +16,42%      Thg 9   +0,69%
Thg 4  +12,17%      Thg 10  +7,79%
Thg 5   +5,06%      Thg 11  +3,14%
Thg 6   +2,36%      Thg 12  +6,23%
</code></pre></div></div>

<p>Cả năm <strong>+42,13%</strong>, và không có tháng nào âm.</p>

<p>Một tài khoản khác trong năm 2024 còn đẹp hơn: +6,24%, +0,54%, +4,08%, +17,94%, +8,27%, +4,08%, <strong>+20,44%</strong>, +10,93%.</p>

<p>Nếu mình dừng bài viết ở đây thì đây là một bài quảng cáo bot rất thuyết phục. Trên mạng đầy bài dừng đúng ở chỗ này.</p>

<h2 id="thứ-đã-cứu-mình-không-phải-là-chiến-lược">Thứ đã cứu mình không phải là chiến lược</h2>

<p>Trước khi kể phần hỏng, phải nói phần này, vì đây là thứ duy nhất mình làm đúng.</p>

<p>Nguyên tắc mình tự đặt và ghi thẳng vào bảng tính: <strong>rút lãi ra cho tới khi thu đủ vốn gốc.</strong> Không để lãi nằm lại trong tài khoản để cộng dồn.</p>

<p>Nên trong bảng tính, cột số dư trông rất kỳ. Tháng 1 năm 2023 số dư 1.250 đô, tháng 2 còn 1.065, tháng 3 còn 790 — trong khi cả ba tháng đều lãi. Số dư giảm vì mình rút ra 200 đô, rồi 450 đô, rồi 50 đô. Riêng tài khoản đó mình rút về <strong>700 đô</strong> trong ba tháng. Một tài khoản khác mình rút về 282,44 đô.</p>

<p>Cách này làm lợi nhuận trông tệ đi rất nhiều. Vốn nhỏ thì lãi nhỏ, và lãi kép gần như không có cơ hội chạy.</p>

<p>Đổi lại, khi mọi thứ hỏng, phần lớn tiền đã không còn nằm ở đó.</p>

<h2 id="rồi-tài-khoản-về-0">Rồi tài khoản về 0</h2>

<p>Tháng 7 năm 2024, một tài khoản lãi 17,67%, số dư lên 237,90 đô. Mình rút 37,90 đô ra theo đúng nguyên tắc.</p>

<p>Dòng tiếp theo trong bảng tính của mình là <strong>-187,10</strong>.</p>

<p>Số dư còn <strong>13,39 đô</strong>. Rồi 0. Cả năm 2024 tài khoản đó lỗ 151,37 đô trên vốn ban đầu 202,17 đô.</p>

<p>Một lệnh xoá sạch tám tháng. Và tám tháng đó có những tháng lãi 17%, 20%.</p>

<h2 id="thứ-hỏng-không-phải-là-chiến-lược">Thứ hỏng không phải là chiến lược</h2>

<p>Đây là phần mình nghĩ đáng đọc nhất, vì nó không nằm trong bất kỳ bài quảng cáo bot nào.</p>

<p><strong>Cái bot chạy trên một cái máy, và máy thì tắt.</strong> Tháng 9 năm 2023 tài khoản đầu tiên chỉ lãi 0,69%, thấp nhất cả năm. Ghi chú của mình ngay cạnh ô đó: <em>“VPS bị tắt mà”</em>. Cả tháng gần như không giao dịch gì vì máy chủ ảo chạy nó đã tắt mà mình không biết. Không phải thị trường xấu. Là hạ tầng.</p>

<p><strong>Phần mềm thì hỏng.</strong> Ghi chú ngày 11/08/2024: <em>“EA bị lỗi phần tin tức”</em>. Bộ lọc tin tức, thứ đáng ra ngăn bot vào lệnh lúc thị trường sắp biến động mạnh, bị lỗi. Ngày 12/06/2024 lại có ghi chú phát hiện bản MT4 đang chạy bị lỗi, phải tải lại và chép đè.</p>

<p><strong>Chi phí ẩn khác nhau tới chín lần giữa các sàn.</strong> Mình có đo spread trên vàng ở bốn sàn và ghi lại:</p>

<table>
  <thead>
    <tr>
      <th>Sàn</th>
      <th>Spread XAU</th>
      <th>Hoa hồng</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Exness</td>
      <td>0,052</td>
      <td>0,07</td>
    </tr>
    <tr>
      <td>Tickmill</td>
      <td>0,21</td>
      <td>0,04</td>
    </tr>
    <tr>
      <td>FBS</td>
      <td>0,37</td>
      <td>—</td>
    </tr>
    <tr>
      <td>RoboMarkets</td>
      <td>0,47</td>
      <td>—</td>
    </tr>
  </tbody>
</table>

<p>Chênh lệch giữa 0,052 và 0,47 là gần chín lần. Với một chiến lược vào lệnh dày, khoản đó ăn thẳng vào kết quả. Đây là số mình đo năm 2024 và mình không giới thiệu sàn nào cả — điều đáng nói là <strong>cùng một con bot, cùng một chiến lược, đặt ở hai nơi khác nhau cho ra hai kết quả khác nhau</strong>, và phần chênh đó không nằm trong bất kỳ bảng lãi nào bạn được xem.</p>

<p>Ba thứ vừa kể — máy chủ, phần mềm, chi phí sàn — đều không phải chuyện thị trường. Chúng là chuyện vận hành. Và chúng đủ để quyết định lãi lỗ.</p>

<h2 id="con-bot-của-mình-là-loại-nhồi-lệnh-theo-lưới">Con bot của mình là loại nhồi lệnh theo lưới</h2>

<p>Tên các tệp cấu hình mình còn lưu nói hết: <code class="language-plaintext highlighter-rouge">..._XAUUSD_M5-DCA.set</code> và <code class="language-plaintext highlighter-rouge">..._Vang_M5-DCAGrid-...</code>. Đây là chiến lược nhồi lệnh — khi giá đi ngược, bot mở thêm lệnh để hạ giá vốn trung bình rồi chờ thị trường quay lại.</p>

<p>Đây là bản kiểm thử mình chạy ngày 17/08/2023, trên vàng khung M5, dữ liệu từ 15/02/2022 tới 31/12/2022:</p>

<p><img src="/assets/images/2026/2026-09-05-bot-vang-ea-sofsog.com03.png" alt="Hình bảng thiết lập kiểm thử EA trên cặp XAUUSD khung M5 sofsog.com" /></p>

<p>Và đây là đường vốn nó vẽ ra:</p>

<p><img src="/assets/images/2026/2026-09-05-bot-vang-ea-sofsog.com01.png" alt="Hình đường vốn kiểm thử đi lên đều rồi rơi thẳng đứng một nhát sofsog.com" /></p>

<p>Nhìn từ trái sang, nó đi lên đều đặn suốt hơn bảy trăm lệnh, từ 793 lên gần 3.900. Rồi <strong>rơi thẳng đứng một nhát xuống 2.774</strong>.</p>

<p>Bảng thống kê của chính lần kiểm thử đó giải thích cái vách:</p>

<p><img src="/assets/images/2026/2026-09-05-bot-vang-ea-sofsog.com02.png" alt="Hình bảng thống kê kết quả kiểm thử với tỷ lệ thắng 87,17 phần trăm sofsog.com" /></p>

<p>Con số đầu tiên ai cũng nhìn là <strong>87,17% lệnh có lãi</strong> — 734 thắng trên 842 lệnh. Gần chín trên mười. Vốn 1.000 đô thành 3.385 đô.</p>

<p>Nhưng ba dòng bên dưới mới là toàn bộ câu chuyện:</p>

<table>
  <thead>
    <tr>
      <th> </th>
      <th> </th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Lệnh lãi trung bình</td>
      <td><strong>+7,97 đô</strong></td>
    </tr>
    <tr>
      <td>Lệnh lỗ trung bình</td>
      <td><strong>−32,10 đô</strong></td>
    </tr>
    <tr>
      <td>Chuỗi thắng dài nhất</td>
      <td>27 lệnh, được <strong>+138,51 đô</strong></td>
    </tr>
    <tr>
      <td>Chuỗi thua dài nhất</td>
      <td>6 lệnh, mất <strong>−1.011,66 đô</strong></td>
    </tr>
  </tbody>
</table>

<p><strong>Hai mươi bảy lệnh thắng liên tiếp kiếm được 138,51 đô. Sáu lệnh thua liên tiếp mất 1.011,66 đô.</strong> Bằng một phần tư số lệnh, mất gấp bảy lần số tiền.</p>

<p>Sụt vốn tối đa 1.395,22 đô, tức <strong>36,34%</strong> tài khoản. Sụt vốn tương đối còn cao hơn: 40,84%.</p>

<p>Đó là hình dạng đặc trưng của nhồi lệnh theo lưới. Nó không thua nhiều lần nhỏ. Nó thắng rất nhiều lần nhỏ, rồi thua một lần rất lớn.</p>

<p>Cần nói rõ một điều về bản kiểm thử này, vì nó là chỗ đa số bảng kết quả trên mạng gian lận được. Dữ liệu mình dùng là <strong>dữ liệu tick mua về</strong>, không phải dữ liệu mặc định của phần mềm, và spread được chỉnh sát với thực tế. Chỉ cần <strong>đặt spread sai một chút thôi là lợi nhuận ảo phình lên khủng khiếp</strong> — phần lớn những đường vốn đẹp không tưởng mà bạn thấy người ta khoe đều đẹp vì lý do đó.</p>

<p>Nhưng kiểm thử chạy chuẩn tới đâu thì nó vẫn chỉ là lịch sử, và <strong>thực tế khác rất nhiều</strong>. Đúng ba thứ kể ở mục trên — máy chủ tắt, phần mềm lỗi, spread thật của từng sàn — không có kiểm thử nào mô phỏng được.</p>

<p>Vậy nên cái vách kia còn đáng sợ hơn. Nó xuất hiện trong điều kiện lý tưởng nhất, trên dữ liệu sạch, không có sự cố vận hành nào. <strong>Nó đã nằm sẵn trong dữ liệu của mình ngay từ đầu.</strong> Mình chỉ nhìn con số 87,17% mà không nhìn cái vách.</p>

<h2 id="kênh-riêng-để-ghi-những-ngày-không-vượt-qua-được">Kênh riêng để ghi những ngày không vượt qua được</h2>

<p>Hồi đó mình lập hẳn một kênh riêng, chỉ để ghi lại những ngày con bot không qua nổi. Sau mấy năm nó có đúng năm dòng:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>30/09/2021  Vàng
19/04/2021  EU
21/02/2022  cuối tháng
06/05/2022  session không qua hồi
28/02/2022  Set 18 DCA không qua được — 0.01 fixlot, 200 balance, 30 spread
</code></pre></div></div>

<p>Mỗi dòng là một ngày giá đi một chiều đủ xa và đủ lâu để lưới lệnh không gỡ lại được.</p>

<p>Nhưng phải nói cho công bằng, và đây là điều mình mất khá lâu mới nhìn ra: <strong>những ngày này chỉ khó vượt qua với một chiến lược nhồi lệnh không cắt lỗ.</strong> Có điểm dừng lỗ và chốt lời rõ ràng thì chúng chỉ là những ngày lỗ bình thường, không phải ngày xoá sổ tài khoản. Thị trường hôm đó không làm gì sai. Thiết kế chiến lược mới là chỗ sai.</p>

<p>Cái lưới không có điểm dừng lỗ nghĩa là <strong>khoản lỗ không có giới hạn trên</strong>. Và mọi con số đẹp ở mục trước đều được mua bằng đúng thứ đó.</p>

<p>Tỷ lệ thắng chín trên mười không phải tự nhiên mà có. Muốn giữ nó đẹp thì phải để lệnh lỗ chạy tiếp và nhồi thêm cho tới khi giá quay lại; muốn giới hạn khoản lỗ thì phải cắt, và tỷ lệ thắng tụt xuống ngay. Mình đã chọn vế đầu trong nhiều năm mà không hiểu rằng mình đang chọn.</p>

<h2 id="bảy-năm-lãi-đều-rồi-cháy-sạch-trong-một-ngày">Bảy năm lãi đều, rồi cháy sạch trong một ngày</h2>

<p>Chuyện của mình là tài khoản 202 đô. Nhưng mình từng chứng kiến bản phóng to của nó.</p>

<p>Vài năm trước mình theo dõi một tín hiệu giao dịch trên <code class="language-plaintext highlighter-rouge">mql5.com</code>, của một tác giả người Nga. Nó lãi đều đặn suốt <strong>bảy năm</strong>. Rất nhiều người sao chép tín hiệu đó, và theo mình nhớ thì tổng số tiền chạy theo lên tới hàng triệu đô.</p>

<p>Rồi một ngày đẹp trời nó cháy sạch. Tất cả những người sao chép cháy theo.</p>

<p>Bảy năm lãi đều là thứ thuyết phục hơn bất kỳ lời quảng cáo nào. Nó trả lời trước mọi hoài nghi. Và nó vẫn không cứu được ai.</p>

<p>Đây là chỗ mình muốn nói thẳng, vì nó là bài học đắt nhất mình có:</p>

<p><strong>Mọi chiến thuật thắng rất nhiều lần nhỏ rồi thua một lần rất lớn đều kết thúc giống nhau. Mọi chiến thuật chịu sụt vốn lớn để gồng lệnh cũng vậy.</strong> Không quan trọng nó đã lãi bao nhiêu năm.</p>

<p>Số năm lãi không làm rủi ro nhỏ đi. Nó chỉ chứng minh rằng trong ngần ấy thời gian chưa gặp cú sốc đủ lớn. Càng chạy lâu thì khả năng gặp đúng một chuỗi thua đủ dài càng tiến về chắc chắn — và vì cỡ lệnh thường đã lớn lên cùng tài khoản, cú đó tới càng muộn thì càng đau.</p>

<p>Nói cách khác: <strong>thời gian không đứng về phía những chiến thuật này.</strong> Nó chỉ làm bạn tin tưởng hơn và nạp vào nhiều hơn trước khi chuyện xảy ra.</p>

<p>Nếu bạn đang nhìn một chiến lược, một con bot hay một tín hiệu có đường vốn đẹp, câu cần hỏi không phải “nó lãi bao nhiêu một tháng” mà là <strong>“lệnh lỗ trung bình so với lệnh lãi trung bình là bao nhiêu”</strong> và <strong>“chuỗi thua dài nhất đã mất bao nhiêu”</strong>. Hai con số đó nằm trong mọi bảng kết quả, và gần như không ai đăng chúng lên.</p>

<h2 id="vì-sao-lãi-42-một-năm-vẫn-không-phải-là-một-kế-hoạch">Vì sao lãi 42% một năm vẫn không phải là một kế hoạch</h2>

<p>Mình có một công thức tính cỡ lệnh, ghi ngay đầu bảng tính:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Vốn tháng sau = Vốn × căn bậc hai của (1 + Lãi đã chốt / Vốn)
</code></pre></div></div>

<p>Ý tưởng là tăng cỡ lệnh theo lãi, nhưng tăng chậm hơn tốc độ lãi để đỡ rủi ro. Nhìn thì cẩn thận. Mình đã khá tự hào về nó.</p>

<p>Nhưng công thức đó chỉ trả lời câu “tăng bao nhiêu”. Nó không trả lời câu quan trọng hơn: <strong>chuyện gì xảy ra nếu có một chuỗi thua đủ lớn.</strong> Và câu trả lời nằm ở dòng -187,10 kia.</p>

<p>Một chiến lược có xác suất mất sạch khác hẳn về bản chất so với một chiến lược lãi ít hơn nhưng không bao giờ về 0. Đem hai thứ đó so bằng con số phần trăm mỗi tháng là so sai đơn vị. Mình đã so sai suốt hai năm, trong khi bảng tính của chính mình có đủ dữ liệu để thấy điều đó.</p>

<h2 id="điều-mình-rút-ra">Điều mình rút ra</h2>

<p>Sau chuyện này mình ngồi cộng lại toàn bộ những gì từng làm: spot altcoin, hợp đồng tương lai BTC, NFT, và EA vàng. Cộng hết lại thì <strong>lỗ</strong>.</p>

<p>Kết luận của mình, và mình biết nó không hấp dẫn:</p>

<p><strong>Không ai biết đỉnh và đáy của một tài sản nằm ở đâu.</strong> Không ai biết trước nó sẽ tăng, sẽ giảm hay đi ngang bao lâu. Mình đã bỏ nhiều năm để cố tìm ra cách biết, và bằng chứng thu được là một bảng tính kết thúc bằng số 0.</p>

<p>Nên bây giờ mình mua đều đặn và giữ dài hạn. Không đoán thời điểm, không đòn bẩy, không có cái máy nào phải bật 24/7. Nhàm chán hơn nhiều, và cũng là thứ duy nhất mình còn tin sau khi đã thử những thứ kia.</p>

<p>Danh mục hiện tại của mình và cách phân bổ, mình sẽ viết ở bài sau của loạt này.</p>

<h2 id="những-gì-bài-này-không-nói">Những gì bài này không nói</h2>

<p>Mình không phải người tư vấn tài chính và không có giấy phép hành nghề. Bài này kể lại chuyện của mình, không phải khuyến nghị cho ai.</p>

<p>Nó cũng không nói rằng mọi EA đều tệ, hay giao dịch tự động thì không thể có lãi. Mình chỉ có dữ liệu về con bot của mình, trên tài khoản của mình, trong ba năm đó. Người khác có kết quả khác là chuyện hoàn toàn có thể.</p>

<p>Và nó đặc biệt không nói rằng bạn nên làm theo mình. Điều duy nhất mình thấy đáng mang đi là câu hỏi này: <strong>nếu chiến lược của bạn gặp một chuỗi thua đủ lớn thì còn lại bao nhiêu?</strong> Nếu câu trả lời là 0, thì con số lãi mỗi tháng không quan trọng như bạn tưởng.</p>

<p>Chúc các bạn thành công.</p>]]></content><author><name>Thành</name></author><category term="tai-chinh" /><category term="chia-se" /><category term="đầu tư" /><category term="forex" /><category term="vàng" /><category term="EA" /><category term="DCA" /><category term="quản lý vốn" /><summary type="html"><![CDATA[Mình nghiên cứu một con bot giao dịch vàng trong nhiều năm. Có tháng nó lãi **20,44%**, có năm lãi **42,13%**. Rồi một tài khoản đi từ 237,90 đô xuống 13,39 đô rồi về 0. Bài này là bảng tính mình còn giữ được, và vì sao mọi chiến thuật kiểu đó đều kết thúc giống nhau.]]></summary></entry><entry><title type="html">NAS hết RAM: zram đầy 100%, gần 1 GB tràn xuống ổ cứng</title><link href="https://sofsog.com/server/nas-het-ram-do-truoc-khi-cai-them" rel="alternate" type="text/html" title="NAS hết RAM: zram đầy 100%, gần 1 GB tràn xuống ổ cứng" /><published>2026-09-05T00:00:00+00:00</published><updated>2026-09-05T00:00:00+00:00</updated><id>https://sofsog.com/server/nas-het-ram-do-truoc-khi-cai-them</id><content type="html" xml:base="https://sofsog.com/server/nas-het-ram-do-truoc-khi-cai-them"><![CDATA[<p>Mình định cài thêm một dịch vụ nữa lên NAS. Trước khi cài thì đo một lượt cho chắc, và số đo cho thấy máy đã hết chỗ từ lâu rồi.</p>

<aside class="series-box" aria-label="Các bài trong series Tự dựng server tại nhà"><p class="series-box__dau">Series <a href="/series/">Tự dựng server tại nhà</a> &middot; bài 8/9 <span class="series-box__cap">Cơ bản</span></p><ol class="series-box__ds"><li><a href="/server/dung-gitea-tren-nas-dong-bo-obsidian-giua-pc-va-dien-thoai">Dựng Gitea trên NAS - "GitHub riêng" để đồng bộ Obsidian giữa PC và điện thoại</a></li><li><a href="/server/tailscale-vao-nas-tu-xa-khong-mo-port">Tailscale - vào NAS từ bất cứ đâu mà không mở port trên router</a></li><li><a href="/server/vaultwarden-tren-nas-kho-mat-khau-cho-ca-nha">Vaultwarden trên NAS - kho mật khẩu cho cả nhà, không trả phí hằng tháng</a></li><li><a href="/server/chon-nas-dau-tien-mua-dung-san-hay-tu-lap">Chọn NAS đầu tiên - mua hộp dựng sẵn hay tự lắp từ máy chủ cũ</a></li><li><a href="/server/quy-tac-3-2-1-lam-cho-that">Quy tắc 3-2-1 làm cho thật - ngồi đếm lại mới biết mình thiếu gì</a></li><li><a href="/server/privatebin-tren-nas-chia-se-text-co-mat-khau">PrivateBin trên NAS - link chia sẻ text có mật khẩu, không giới hạn 31 ngày</a></li><li><a href="/server/nodewarden-hay-vaultwarden-chot-cai-nao">NodeWarden hay Vaultwarden - chạy song song mấy tháng rồi mình chốt cái nào</a></li><li class="dang-doc" aria-current="true">NAS hết RAM: zram đầy 100%, gần 1 GB tràn xuống ổ cứng</li><li><a href="/server/keo-154-repo-github-ve-nas-bang-gitea">Kéo 154 repo GitHub về NAS: mirror tự cập nhật bằng Gitea</a></li></ol></aside>

<p>Bài này là ba lệnh để tự đo, cách đọc kết quả cho đúng, và một chuyện khó nói hơn: phần lớn RAM của mình đang bị chiếm bởi những thứ mình không còn dùng.</p>

<h2 id="ba-con-số">Ba con số</h2>

<p>Con NAS 4 GB của mình, uptime 28 ngày 17 giờ, đang trong tình trạng này:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>              total        used        free      shared  buff/cache   available
Mem:           3458        2679         132          54         646         487
Swap:          4121        3028        1093
</code></pre></div></div>

<p><strong>RAM còn thật sự dùng được: 487 MB.</strong> Không phải cột <code class="language-plaintext highlighter-rouge">free</code> (132 MB) — cột đó luôn thấp và không nói lên điều gì, vì nhân giữ bộ đệm đĩa ở <code class="language-plaintext highlighter-rouge">buff/cache</code> và sẽ trả lại khi cần. Cột đáng nhìn là <code class="language-plaintext highlighter-rouge">available</code>.</p>

<p><strong>Swap đã dùng 3.028 MB trên 4.121 MB.</strong> Nhưng con số này một mình vẫn chưa kết luận được gì, và đó là chỗ mình sẽ nói kỹ bên dưới.</p>

<p><strong>Nhân đang đọc swap 285 KB/s</strong> trong lúc máy gần như rảnh. Đây mới là con số làm mình dừng tay.</p>

<h2 id="lệnh-1-xem-swap-nằm-ở-đâu">Lệnh 1: xem swap nằm ở đâu</h2>

<p>Đây là lệnh mà mình nghĩ nhiều người bỏ qua. <code class="language-plaintext highlighter-rouge">free</code> gộp tất cả swap vào một dòng, nhưng swap có thể nằm ở hai chỗ rất khác nhau về hậu quả:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cat</span> /proc/swaps
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Filename                Type            Size      Used    Priority
/dev/md1                partition       2096124   977612  -1
/dev/zram0              partition       2124796   2122532  1
</code></pre></div></div>

<p>Hai dòng, hai câu chuyện khác hẳn.</p>

<p><code class="language-plaintext highlighter-rouge">/dev/zram0</code> là <strong>swap nằm trong chính RAM</strong>, dữ liệu được nén lại. Đẩy trang vào đây tốn CPU để nén, nhưng không hề chạm vào ổ cứng, nên nhanh. Nó đang dùng 2.122.532 trên 2.124.796 KB — <strong>đầy 99,9%</strong>.</p>

<p><code class="language-plaintext highlighter-rouge">/dev/md1</code> là swap <strong>trên đĩa thật</strong>, nằm trên chính mảng ổ cứng chứa dữ liệu của bạn. Nó đang giữ 977.612 KB, tức gần 1 GB.</p>

<p>Cột <code class="language-plaintext highlighter-rouge">Priority</code> giải thích thứ tự: zram có ưu tiên <code class="language-plaintext highlighter-rouge">1</code>, cao hơn <code class="language-plaintext highlighter-rouge">-1</code> của đĩa, nên nhân dùng zram trước. Gần 1 GB nằm trên đĩa nghĩa là <strong>zram đã đầy tới mức nhân buộc phải tràn xuống ổ cứng</strong>. Đó không còn là chuyện tối ưu nữa.</p>

<h2 id="lệnh-2-đo-xem-swap-có-đang-bị-đọc-ghi-liên-tục-không">Lệnh 2: đo xem swap có đang bị đọc ghi liên tục không</h2>

<p>Đây là phép đo quan trọng nhất trong bài, và cũng là thứ hầu như không hướng dẫn nào nhắc.</p>

<p><strong>Swap có dữ liệu không đồng nghĩa với máy đang chậm.</strong> Nhân đẩy các trang nguội — thứ nạp lúc khởi động rồi không đụng tới nữa — ra swap là hành vi đúng, nó giải phóng RAM cho việc có ích. Một máy có 3 GB swap toàn trang nguội vẫn chạy mượt.</p>

<p>Vấn đề chỉ xuất hiện khi nhân phải <strong>đọc đi đọc lại</strong> swap, vì thứ nằm trong đó vẫn đang được dùng. Muốn biết thì phải đo tốc độ, không phải đo dung lượng.</p>

<p>DSM không có <code class="language-plaintext highlighter-rouge">vmstat</code>, nhưng bộ đếm nằm sẵn trong nhân. Lấy hai mẫu cách nhau 15 giây rồi chia ra:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">a</span><span class="o">=</span><span class="si">$(</span><span class="nb">grep</span> <span class="nt">-E</span> <span class="s2">"^pswpin|^pswpout"</span> /proc/vmstat<span class="si">)</span><span class="p">;</span> <span class="nb">sleep </span>15
<span class="nv">b</span><span class="o">=</span><span class="si">$(</span><span class="nb">grep</span> <span class="nt">-E</span> <span class="s2">"^pswpin|^pswpout"</span> /proc/vmstat<span class="si">)</span>
<span class="nb">echo</span> <span class="s2">"</span><span class="nv">$a</span><span class="s2">"</span><span class="p">;</span> <span class="nb">echo</span> <span class="s2">"</span><span class="nv">$b</span><span class="s2">"</span>
</code></pre></div></div>

<p>Mỗi trang là 4 KB, nên lấy hiệu số nhân 4 rồi chia cho 15 là ra KB/s. Máy mình trong 15 giây đó:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>doc tu swap  (swap-in) : 1069 trang -&gt; 285 KB/s
ghi ra swap (swap-out):  327 trang -&gt;  87 KB/s
</code></pre></div></div>

<p>Máy đang <strong>đọc từ swap 285 KB/s liên tục</strong> trong lúc không ai dùng gì. Nghĩa là dữ liệu nằm trong swap không phải trang nguội — nó là thứ các tiến trình vẫn cần, và nhân phải lôi ra vào suốt.</p>

<p>Con số cộng dồn từ lúc khởi động còn rõ hơn:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">grep</span> <span class="nt">-E</span> <span class="s2">"^pswpin|^pswpout"</span> /proc/vmstat
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pswpin 13294756
pswpout 11598748
</code></pre></div></div>

<p>Nhân 4 KB: <strong>53 GB đã đọc ra từ swap và 46 GB đã ghi vào swap</strong> trong 28 ngày. Phần rơi xuống <code class="language-plaintext highlighter-rouge">/dev/md1</code> là ghi thật lên ổ cứng.</p>

<p>Nếu máy bạn đo ra vài KB/s hoặc bằng không thì swap đầy tới đâu cũng không sao. Nếu ra hàng trăm KB/s như của mình thì máy đang bù RAM bằng đĩa, và mọi thứ chậm đi một cách khó chỉ mặt đặt tên.</p>

<h2 id="lệnh-3-ai-đang-ăn-ram">Lệnh 3: ai đang ăn RAM</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ps <span class="nt">-eo</span> rss,args <span class="nt">--sort</span><span class="o">=</span><span class="nt">-rss</span> | <span class="nb">head</span> <span class="nt">-15</span>
</code></pre></div></div>

<p>Máy mình, đơn vị KB:</p>

<table>
  <thead>
    <tr>
      <th>RSS (KB)</th>
      <th>Tiến trình</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>428.324</td>
      <td>AdGuard Home (lọc quảng cáo DNS)</td>
    </tr>
    <tr>
      <td>355.016</td>
      <td>một trình quản lý tải file chạy trên Java</td>
    </tr>
    <tr>
      <td>148.672</td>
      <td>Jellyfin (máy chủ phim)</td>
    </tr>
    <tr>
      <td>103.720</td>
      <td>một dịch vụ Node</td>
    </tr>
    <tr>
      <td>80.920</td>
      <td>Gitea</td>
    </tr>
    <tr>
      <td>51.508</td>
      <td><code class="language-plaintext highlighter-rouge">synoelasticd</code> — bộ đánh chỉ mục tìm kiếm của DSM</td>
    </tr>
    <tr>
      <td>35.608</td>
      <td><code class="language-plaintext highlighter-rouge">dockerd</code></td>
    </tr>
    <tr>
      <td>34.380</td>
      <td><code class="language-plaintext highlighter-rouge">Xvnc</code> — máy chủ màn hình từ xa</td>
    </tr>
    <tr>
      <td>29.128</td>
      <td>tiến trình đồng bộ của Synology Drive</td>
    </tr>
    <tr>
      <td>24.744</td>
      <td><code class="language-plaintext highlighter-rouge">tailscaled</code></td>
    </tr>
  </tbody>
</table>

<p>Một lưu ý phải nói kẻo bạn cộng nhầm: <strong>RSS đếm cả phần bộ nhớ dùng chung</strong>, nên cộng cả cột lại sẽ ra số lớn hơn lượng RAM thật đang bị chiếm. Dùng nó để xếp hạng ai nặng ai nhẹ thì đúng, dùng để tính tổng thì sai.</p>

<p>Còn một cách nhìn khác, gọn hơn:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">grep </span>Committed_AS /proc/meminfo
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Committed_AS:   11060624 kB
</code></pre></div></div>

<p>Tổng bộ nhớ mà nhân đã <strong>hứa</strong> cấp cho các tiến trình là 10,5 GB, trên một cái máy có 3,4 GB. Nhân cho phép hứa vượt vì phần lớn chương trình xin nhiều hơn mức thật sự đụng tới. Nhưng tỷ lệ hứa gấp ba lần thực có là dấu hiệu máy đang gánh nhiều hơn khả năng của nó.</p>

<h2 id="chỗ-khó-nói-mình-cài-rồi-không-dùng">Chỗ khó nói: mình cài rồi không dùng</h2>

<p>Nhìn lại bảng trên và tự hỏi từng dòng “tuần vừa rồi mình có mở nó không”, kết quả không đẹp.</p>

<p>Cái ăn nhiều thứ hai, 355 MB, là một trình quản lý tải file mình cài từ rất lâu và gần như không còn mở tới. Nó là ứng dụng Java, mà JVM thì giữ chặt vùng heap đã xin kể cả lúc ngồi không. <code class="language-plaintext highlighter-rouge">Xvnc</code> chiếm thêm 34 MB cho một màn hình từ xa mình chưa dùng lần nào trong tháng. Jellyfin 148 MB trong khi nhà mình xem phim bằng thứ khác. <code class="language-plaintext highlighter-rouge">synoelasticd</code> 51 MB là bộ đánh chỉ mục tìm kiếm của DSM, chạy để phục vụ một ô tìm kiếm mình gần như không gõ vào.</p>

<p>Cộng riêng bốn thứ đó đã khoảng <strong>590 MB</strong>, hơn cả lượng RAM còn trống của cả máy.</p>

<p>Trong khi đó những dịch vụ mình thật sự dùng hằng ngày lại rất nhẹ: Gitea 80 MB, Tailscale 24 MB, Vaultwarden và PrivateBin thậm chí không lọt nổi vào bảng. <strong>Cái làm NAS hết RAM không phải là những thứ mình dựng có chủ đích, mà là những thứ mình cài thử rồi quên.</strong></p>

<p>Đây là kiểu tích tụ rất dễ xảy ra với NAS, vì cài một gói chỉ mất vài cú bấm và không có gì nhắc bạn rằng nó vẫn đang chạy sau đó hai năm.</p>

<h2 id="về-swappiness-trên-nas">Về <code class="language-plaintext highlighter-rouge">swappiness</code> trên NAS</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cat</span> /proc/sys/vm/swappiness
</code></pre></div></div>

<p>Máy mình trả về <code class="language-plaintext highlighter-rouge">60</code>, là mặc định. Con <a href="/server/bao-mat-vps-ubuntu-36802-lan-do-mat-khau">VPS mình vừa gia cố tuần này</a> đặt <code class="language-plaintext highlighter-rouge">10</code>.</p>

<p>Khác biệt đó có lý do. Trên VPS không có zram, swap nằm thẳng trên đĩa, nên đẩy ra swap là chậm thật và để <code class="language-plaintext highlighter-rouge">10</code> là hợp lý. Trên NAS có zram, swap ưu tiên nằm trong RAM nén, nên nhân sốt sắng đẩy ra một chút cũng không hại gì — <code class="language-plaintext highlighter-rouge">60</code> không phải con số sai.</p>

<p>Nhưng nó chỉ đúng <strong>khi zram còn chỗ</strong>. Zram của mình đã đầy 99,9%, nên bây giờ mỗi lần nhân quyết định đẩy một trang ra swap, chỗ duy nhất còn nhận là ổ cứng. Hạ <code class="language-plaintext highlighter-rouge">swappiness</code> xuống lúc này chỉ là bịt triệu chứng. Cái sai không nằm ở tham số, mà ở chỗ máy đang chạy nhiều hơn mức RAM cho phép.</p>

<h2 id="vậy-mình-làm-gì">Vậy mình làm gì</h2>

<p>Mình <strong>không cài thêm dịch vụ mới</strong>, dù đã lên kế hoạch viết bài về nó. Cài một ứng dụng Node vào lúc này là đẩy máy tràn xuống đĩa sâu hơn và làm chậm mọi thứ đang chạy, đổi lấy một bài viết. Không đáng.</p>

<p>Thứ tự mình sẽ làm là gỡ trước, nâng sau. Gỡ hẳn những gói không còn dùng — gỡ chứ không chỉ tắt, vì gói đã tắt vẫn có thể tự bật lại sau khi cập nhật DSM. Ước tính thu về khoảng 500–600 MB, đủ để zram thôi đầy và máy thôi ghi swap xuống đĩa.</p>

<p>Nhưng phải nói thẳng: <strong>dọn dẹp chỉ mua thêm thời gian.</strong> Nó đưa máy về trạng thái lành mạnh với đúng số dịch vụ hiện tại, chứ không tạo ra chỗ cho dịch vụ mới. Muốn chạy thêm thì phải nâng RAM, không có đường tắt nào khác.</p>

<p>Và đây là bài học vòng lại <a href="/server/chon-nas-dau-tien-mua-dung-san-hay-tu-lap">bài chọn NAS đầu tiên</a>: lúc mua, 4 GB nghe rất thoải mái cho “một cái ổ cứng mạng”. Nó chỉ chật khi bạn bắt đầu tự host thật, và lúc đó thì khe RAM còn trống hay không đã được quyết định từ lâu rồi. Nếu bạn đang chọn máy, đây là lý do mình khuyên nhìn khả năng nâng RAM trước khi nhìn số khay ổ cứng.</p>

<h2 id="đo-lại-sau-khi-dọn">Đo lại sau khi dọn</h2>

<p>Đừng tin cảm giác “hình như nhanh hơn”. Ghi lại ba con số trước khi dọn, dọn xong đo lại đúng ba con số đó:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>free <span class="nt">-m</span> | <span class="nb">head</span> <span class="nt">-3</span>
<span class="nb">cat</span> /proc/swaps
<span class="nb">grep</span> <span class="nt">-E</span> <span class="s2">"^pswpin|^pswpout"</span> /proc/vmstat
</code></pre></div></div>

<p>Hai chỉ số cần thay đổi là <strong><code class="language-plaintext highlighter-rouge">available</code> tăng lên</strong> và <strong>tốc độ swap-in tụt về gần 0</strong>. Riêng dòng <code class="language-plaintext highlighter-rouge">/dev/md1</code> trong <code class="language-plaintext highlighter-rouge">/proc/swaps</code> sẽ không tự giảm ngay, vì nhân không chủ động kéo trang từ đĩa về khi RAM vừa trống ra. Muốn dọn sạch phần đó thì tắt bật lại swap, và chỉ làm khi RAM đã đủ trống để nhận hết:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>swapoff <span class="nt">-a</span> <span class="o">&amp;&amp;</span> <span class="nb">sudo </span>swapon <span class="nt">-a</span>
</code></pre></div></div>

<p>Làm lệnh này lúc RAM còn chật là cách nhanh nhất để máy bị nhân giết tiến trình. Đo trước, chắc chắn <code class="language-plaintext highlighter-rouge">available</code> đã lớn hơn lượng swap đang dùng, rồi mới chạy.</p>

<p>Chúc các bạn thành công.</p>

<h2 id="link-tham-khảo">Link tham khảo</h2>

<p><a href="https://www.kernel.org/doc/Documentation/blockdev/zram.txt">https://www.kernel.org/doc/Documentation/blockdev/zram.txt</a></p>

<p><a href="https://docs.kernel.org/filesystems/proc.html">https://docs.kernel.org/filesystems/proc.html</a></p>]]></content><author><name>Thành</name></author><category term="server" /><category term="thu-thuat-chung" /><category term="NAS" /><category term="RAM" /><category term="swap" /><category term="zram" /><category term="Docker" /><category term="Synology" /><summary type="html"><![CDATA[Mình định cài thêm một dịch vụ nữa lên NAS. Đo trước cho chắc, và phát hiện máy đã hết chỗ từ lâu: **zram đầy 99,9%**, gần 1 GB tràn xuống ổ cứng, và nhân đang đọc swap **285 KB/s** ngay lúc máy gần như rảnh. Bài này là ba lệnh để tự đo, và cách đọc kết quả cho đúng.]]></summary></entry><entry><title type="html">Chọn NAS đầu tiên - mua hộp dựng sẵn hay tự lắp từ máy chủ cũ</title><link href="https://sofsog.com/server/chon-nas-dau-tien-mua-dung-san-hay-tu-lap" rel="alternate" type="text/html" title="Chọn NAS đầu tiên - mua hộp dựng sẵn hay tự lắp từ máy chủ cũ" /><published>2026-09-04T00:00:00+00:00</published><updated>2026-09-04T00:00:00+00:00</updated><id>https://sofsog.com/server/chon-nas-dau-tien-mua-dung-san-hay-tu-lap</id><content type="html" xml:base="https://sofsog.com/server/chon-nas-dau-tien-mua-dung-san-hay-tu-lap"><![CDATA[<p>Ba bài trước của series này đều bắt đầu bằng câu “bạn cần một con NAS”. Bài này trả lời câu hỏi đứng trước tất cả: nên mua hộp dựng sẵn hay tự lắp từ máy chủ cũ.</p>

<aside class="series-box" aria-label="Các bài trong series Tự dựng server tại nhà"><p class="series-box__dau">Series <a href="/series/">Tự dựng server tại nhà</a> &middot; bài 4/9 <span class="series-box__cap">Cơ bản</span></p><ol class="series-box__ds"><li><a href="/server/dung-gitea-tren-nas-dong-bo-obsidian-giua-pc-va-dien-thoai">Dựng Gitea trên NAS - "GitHub riêng" để đồng bộ Obsidian giữa PC và điện thoại</a></li><li><a href="/server/tailscale-vao-nas-tu-xa-khong-mo-port">Tailscale - vào NAS từ bất cứ đâu mà không mở port trên router</a></li><li><a href="/server/vaultwarden-tren-nas-kho-mat-khau-cho-ca-nha">Vaultwarden trên NAS - kho mật khẩu cho cả nhà, không trả phí hằng tháng</a></li><li class="dang-doc" aria-current="true">Chọn NAS đầu tiên - mua hộp dựng sẵn hay tự lắp từ máy chủ cũ</li><li><a href="/server/quy-tac-3-2-1-lam-cho-that">Quy tắc 3-2-1 làm cho thật - ngồi đếm lại mới biết mình thiếu gì</a></li><li><a href="/server/privatebin-tren-nas-chia-se-text-co-mat-khau">PrivateBin trên NAS - link chia sẻ text có mật khẩu, không giới hạn 31 ngày</a></li><li><a href="/server/nodewarden-hay-vaultwarden-chot-cai-nao">NodeWarden hay Vaultwarden - chạy song song mấy tháng rồi mình chốt cái nào</a></li><li><a href="/server/nas-het-ram-do-truoc-khi-cai-them">NAS hết RAM: zram đầy 100%, gần 1 GB tràn xuống ổ cứng</a></li><li><a href="/server/keo-154-repo-github-ve-nas-bang-gitea">Kéo 154 repo GitHub về NAS: mirror tự cập nhật bằng Gitea</a></li></ol></aside>

<p>Mình sẽ không dẫn giá, vì giá phần cứng thay đổi liên tục và giá mình mua vài năm trước không còn nói lên điều gì. Thay vào đó là số liệu thật từ máy đang chạy, và một kết luận đi ngược với thứ hầu hết người mua lần đầu quan tâm.</p>

<h2 id="hai-đường-đi">Hai đường đi</h2>

<p><strong>Mua hộp dựng sẵn</strong> nghĩa là mua một thiết bị đóng hộp của Synology, QNAP hay Asustor. Cắm điện, cắm mạng, mở trình duyệt là dùng được. Phần mềm do hãng làm sẵn, có kho ứng dụng, có bảo hành, có nơi để gọi khi hỏng.</p>

<p><strong>Tự lắp</strong> nghĩa là mua một máy chủ nhỏ cũ hoặc dựng máy từ linh kiện, rồi cài hệ điều hành lưu trữ lên. Cùng số tiền, bạn được nhiều RAM hơn, CPU khoẻ hơn và nhiều khay ổ hơn. Đổi lại bạn tự lo mọi thứ, và không có bộ phận hỗ trợ nào.</p>

<p>Khác biệt thật không nằm ở tiền. Nó nằm ở chỗ <strong>bạn muốn tiêu thời gian vào việc gì</strong>. Hộp dựng sẵn bán cho bạn thời gian. Tự lắp bán cho bạn phần cứng.</p>

<h2 id="máy-của-mình-là-gì">Máy của mình là gì</h2>

<p>Một con <strong>HPE ProLiant MicroServer Gen10</strong>, CPU AMD Opteron X3421 bốn nhân, ba ổ cứng. Đây là dòng máy chủ nhỏ cho văn phòng, mua lại được với giá dễ chịu vì doanh nghiệp thải ra khá nhiều.</p>

<p>Nói thẳng một chuyện để bạn khỏi hiểu nhầm khi đọc các bài khác trong series: máy của mình đang chạy <strong>DSM</strong>, hệ điều hành của Synology, trên phần cứng không phải Synology. Cách này chạy được và nhiều người làm, nhưng nó <strong>trái với điều khoản giấy phép của Synology</strong>, nên mình không hướng dẫn ở đây và cũng không khuyên bạn làm theo.</p>

<p>Nếu bạn tự lắp, đường chính thống là các hệ điều hành sinh ra cho việc đó: <strong>TrueNAS</strong>, <strong>OpenMediaVault</strong>, hoặc <strong>Unraid</strong>. Cả ba đều chạy Docker, tức là mọi thứ mình viết trong series này — Gitea, Vaultwarden, Tailscale — đều dùng được.</p>

<h2 id="thứ-hết-trước-không-phải-cpu">Thứ hết trước không phải CPU</h2>

<p>Đây là phần đáng giá nhất của bài, và nó đến từ một máy chạy liên tục chứ không phải từ bảng thông số.</p>

<p>Máy của mình đã chạy <strong>27 ngày không nghỉ</strong>, phục vụ hơn chục container. Tải trung bình:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>load average: 0.25, 0.31, 0.50   (trên 4 nhân)
</code></pre></div></div>

<p>Bốn nhân mà tải chỉ 0,25. CPU gần như ngồi chơi.</p>

<p>Còn bộ nhớ:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>              total        used        free      available
Mem:          3.4Gi       2.6Gi       143Mi         547Mi
</code></pre></div></div>

<p>Tổng 3,4 GB, còn trống <strong>547 MB</strong>. Đây mới là chỗ sắp nghẹt.</p>

<p>Nhìn vào các tiến trình ngốn nhất thì hiểu vì sao:</p>

<table>
  <thead>
    <tr>
      <th>Dịch vụ</th>
      <th>RAM</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>AdGuard Home</td>
      <td>437 MB</td>
    </tr>
    <tr>
      <td>Java (ứng dụng của DSM)</td>
      <td>379 MB</td>
    </tr>
    <tr>
      <td>Jellyfin</td>
      <td>169 MB</td>
    </tr>
    <tr>
      <td>Node</td>
      <td>110 MB</td>
    </tr>
    <tr>
      <td>Gitea</td>
      <td>90 MB</td>
    </tr>
  </tbody>
</table>

<p>Không dịch vụ nào bắt CPU làm việc quá vài giây, nhưng mỗi dịch vụ đều chiếm một phần bộ nhớ <strong>và giữ nguyên phần đó suốt thời gian chạy</strong>. Thêm một container là thêm vài trăm MB nằm đó vĩnh viễn, trong khi CPU chỉ bận vài giây rồi lại rảnh.</p>

<p>Kết luận cho người sắp mua: <strong>đừng so kè CPU, hãy nhìn RAM tối đa mà máy đó hỗ trợ và giá nâng RAM</strong>. Một con NAS hai khe RAM nâng được lên nhiều sẽ sống lâu hơn hẳn một con CPU mạnh mà hàn chết 2 GB.</p>

<h2 id="ổ-cứng-và-thứ-raid-không-làm-được">Ổ cứng và thứ RAID không làm được</h2>

<p>Mình dùng ba ổ <strong>Seagate IronWolf 2 TB</strong>, loại chuyên cho NAS. Ổ chuyên NAS khác ổ máy bàn ở chỗ nó được thiết kế để quay liên tục và để chịu rung khi nhiều ổ nằm sát nhau trong cùng một khay.</p>

<p>Ba ổ đó chạy <strong>RAID 5</strong>, cho ra 3,5 TB dùng được. RAID 5 chịu được <strong>một ổ chết</strong>: rút ổ hỏng ra, cắm ổ mới vào, dữ liệu tự dựng lại.</p>

<p>Nhưng RAID không phải backup, và chỗ này mình đã viết kỹ trong <a href="/ke-toan/luu-tru-chung-tu-ke-toan-10-nam">bài về lưu trữ chứng từ kế toán</a>. Tóm tắt lại: RAID chép mọi thao tác sang mọi ổ ngay lập tức, kể cả thao tác xoá nhầm. Nó chống ổ hỏng, không chống bạn, không chống mã độc, và không chống cháy.</p>

<p>Vì vậy khi tính tiền mua NAS, hãy cộng luôn tiền cho một ổ cứng ngoài để backup. Nó không phải phần tuỳ chọn.</p>

<h2 id="bao-nhiêu-dung-lượng-là-đủ">Bao nhiêu dung lượng là đủ</h2>

<p>Chỗ này người ta hay mua thừa nhất.</p>

<p>3,5 TB của mình hiện dùng <strong>53%</strong>, sau nhiều năm chứa ảnh, phim, dữ liệu Docker của hơn chục dịch vụ, và bản sao lưu của mấy máy tính trong nhà.</p>

<p>Không lưu phim thì nhu cầu nhỏ hơn nhiều. Nhớ lại con số ở bài trước: mười năm chứng từ kế toán của một doanh nghiệp nhỏ chỉ khoảng 150–250 GB, còn kho mật khẩu Vaultwarden của mình vỏn vẹn 8,4 MB.</p>

<p>Cách tính hợp lý là ước lượng nhu cầu hiện tại rồi nhân đôi, đừng nhân mười. Ổ cứng năm sau vừa rẻ hơn vừa lớn hơn, và một con NAS còn khay trống thì nâng lúc nào cũng được.</p>

<h2 id="vậy-nên-mua-gì">Vậy nên mua gì</h2>

<p>Mình không né câu này bằng cách nói mỗi lựa chọn đều có cái hay riêng.</p>

<p>Chọn <strong>hộp dựng sẵn</strong> nếu đây là lần đầu bạn tự dựng thứ gì, hoặc nếu con NAS sẽ giữ dữ liệu mà người khác trong nhà hay trong công ty phụ thuộc vào. Khi hỏng lúc nửa đêm, việc có một nơi để gọi và một giao diện đã được kiểm thử kỹ đáng giá hơn số tiền tiết kiệm được.</p>

<p><strong>Tự lắp từ máy chủ cũ</strong> nếu bạn thấy việc mày mò là phần vui chứ không phải phần phiền, và chấp nhận rằng mọi sự cố là việc của mình. Cùng số tiền bạn được nhiều RAM và nhiều khay ổ hơn hẳn — mà RAM lại đúng là thứ hết trước.</p>

<p>Điều mình khuyên cả hai nhóm giống nhau: <strong>mua ổ chuyên NAS</strong>, và <strong>đừng mua con rẻ nhất chỉ có một khe RAM</strong>.</p>

<h2 id="nếu-làm-lại">Nếu làm lại</h2>

<p>Thứ mình làm khác là mua nhiều RAM hơn ngay từ đầu.</p>

<p>Lúc chọn máy, mình nhìn số nhân CPU và số khay ổ, rồi nghĩ 4 GB là thoải mái. Hai năm sau, CPU vẫn rảnh còn bộ nhớ chỉ còn 547 MB, và mỗi lần muốn thêm một dịch vụ mình lại phải cân nhắc xem có đủ RAM không. Nâng RAM sau vẫn được, nhưng phải tắt máy, tháo ra, và mua đúng loại máy đó nhận.</p>

<p>Đó là thứ không có trong bảng thông số nào, chỉ hiện ra sau vài trăm ngày chạy thật.</p>

<p>Chúc các bạn thành công.</p>

<h2 id="link-tham-khảo">Link tham khảo</h2>

<p><a href="https://www.truenas.com/">https://www.truenas.com/</a></p>

<p><a href="https://www.openmediavault.org/">https://www.openmediavault.org/</a></p>

<p><a href="https://www.snapraid.it/faq#raidvsbackup">https://www.snapraid.it/faq#raidvsbackup</a></p>]]></content><author><name>Thành</name></author><category term="server" /><category term="thu-thuat-chung" /><category term="NAS" /><category term="phần cứng" /><category term="RAID" /><category term="HPE MicroServer" /><category term="TrueNAS" /><summary type="html"><![CDATA[Người mua NAS lần đầu thường so kè **CPU** và **dung lượng ổ cứng**. Máy của mình chạy liên tục 27 ngày cho thấy thứ hết trước lại là **RAM** — CPU vẫn nhàn rỗi trong khi bộ nhớ chỉ còn trống hơn 500 MB.]]></summary></entry><entry><title type="html">Lưu trữ chứng từ kế toán 10 năm - dựng kho tài liệu ở văn phòng thay vì Google Drive</title><link href="https://sofsog.com/ke-toan/luu-tru-chung-tu-ke-toan-10-nam" rel="alternate" type="text/html" title="Lưu trữ chứng từ kế toán 10 năm - dựng kho tài liệu ở văn phòng thay vì Google Drive" /><published>2026-09-04T00:00:00+00:00</published><updated>2026-09-04T00:00:00+00:00</updated><id>https://sofsog.com/ke-toan/luu-tru-chung-tu-ke-toan-10-nam</id><content type="html" xml:base="https://sofsog.com/ke-toan/luu-tru-chung-tu-ke-toan-10-nam"><![CDATA[<p>Ngày 11 tháng 9 năm 2020, văn phòng công ty mình cháy. Hồ sơ kế toán bằng giấy mất một phần, còn dữ liệu trong máy tính thì mất sạch vì ổ cứng hỏng hoàn toàn. Cả hai bản lưu đều nằm trong cùng một căn phòng, nên một đám cháy xoá được cả hai cùng lúc.</p>

<p>Bài này là những gì mình rút ra sau hôm đó, viết cho người làm kế toán chứ không phải cho dân IT.</p>

<h2 id="luật-yêu-cầu-gì">Luật yêu cầu gì</h2>

<p>Nghị định 174/2016/NĐ-CP chia tài liệu kế toán thành ba mốc thời hạn. Điều 12 là nhóm giữ tối thiểu <strong>5 năm</strong>. Điều 13 là nhóm tối thiểu <strong>10 năm</strong>, gồm chứng từ dùng trực tiếp để ghi sổ và lập báo cáo tài chính, cùng tài liệu liên quan tới thanh lý và nhượng bán tài sản cố định. Điều 14 là nhóm giữ <strong>vĩnh viễn</strong>. Điều 15 nói thời hạn tính từ lúc nào.</p>

<p>Phần đáng chú ý hơn nằm ở Luật Kế toán 2015: <strong>được phép lưu trữ trên phương tiện điện tử</strong>, không bắt buộc in hết ra giấy. Nhưng kèm ba điều kiện — dữ liệu phải <strong>an toàn</strong>, phải <strong>bảo mật</strong>, và phải <strong>tra cứu được trong suốt thời hạn lưu trữ</strong>.</p>

<p>Có một điểm phân biệt dễ nhầm. Đơn vị kế toán nhà nước vẫn phải in sổ kế toán tổng hợp ra giấy để lưu. Với doanh nghiệp, việc in chứng từ và sổ chi tiết do người đại diện theo pháp luật quyết định.</p>

<p>Mình là kế toán chứ không phải luật sư. Các số điều ở trên bạn nên tự đối chiếu với văn bản gốc trước khi áp dụng cho đơn vị mình, nhất là khi đơn vị bạn có đặc thù riêng.</p>

<p>Ba điều kiện kia nghe như ngôn ngữ pháp lý, nhưng dịch sang việc thật thì rất cụ thể: <strong>đừng để mất, đừng để người ngoài đọc được, và mười năm sau vẫn phải mở ra xem được</strong>. Phần còn lại của bài là cách làm ba việc đó.</p>

<h2 id="mười-năm-dữ-liệu-nhỏ-hơn-bạn-tưởng">Mười năm dữ liệu nhỏ hơn bạn tưởng</h2>

<p>Trước khi bàn cách lưu, cần biết phải lưu bao nhiêu. Con số hay bị hình dung sai theo hướng phóng đại.</p>

<p>Ở công ty chính của mình, riêng máy của kế toán trưởng chứa khoảng <strong>10 GB trong hai năm</strong>. Phòng kế toán có năm người. Nếu bốn người còn lại phát sinh ít hơn, ước chừng cả phòng rơi vào <strong>15–25 GB mỗi năm</strong>. Mười năm là khoảng 150–250 GB. Mấy công ty phụ thì khối lượng chỉ bằng chừng một phần mười.</p>

<p>Đây là ước lượng từ một trường hợp cụ thể, không phải con số chuẩn cho mọi doanh nghiệp. Nhưng bậc độ lớn thì đáng tin: <strong>toàn bộ mười năm chứng từ của một doanh nghiệp nhỏ nằm gọn trong một ổ cứng phổ thông</strong>.</p>

<p>Nghĩa là dung lượng không phải vấn đề. Vấn đề là dữ liệu có sống nổi mười năm không, và tìm lại được không.</p>

<h2 id="vì-sao-google-drive-cá-nhân-không-giải-được-bài-này">Vì sao Google Drive cá nhân không giải được bài này</h2>

<p>Drive đồng bộ tốt, tìm kiếm tốt, và ai cũng biết dùng. Mình không chê công cụ. Chỗ hỏng nằm ở quyền sở hữu và vòng đời.</p>

<p>Thư mục đó thuộc <strong>tài khoản cá nhân của một người</strong>. Người đó nghỉ việc, đổi mật khẩu, hoặc đơn giản là không nghe máy — công ty mất quyền vào kho chứng từ của chính mình. Đây không phải tình huống giả định, nó xảy ra mỗi khi có người rời phòng kế toán.</p>

<p>Quyền chia sẻ cũng loang ra theo thời gian mà không ai rà lại. Sau vài năm, thường không còn ai trả lời chính xác được câu hỏi ai đang đọc được thư mục đó.</p>

<p>Và Drive không có khái niệm thời hạn lưu trữ. Ai đó xoá nhầm một thư mục, ba mươi ngày sau thùng rác tự dọn, thế là xong. Không có gì trong hệ thống ràng buộc rằng tập tài liệu này phải sống đủ mười năm.</p>

<h2 id="raid-không-phải-là-backup">RAID không phải là backup</h2>

<p>Chỗ này mình muốn nói kỹ, vì đây là hiểu nhầm khiến người ta mất dữ liệu trong khi vẫn đinh ninh mình đã an toàn.</p>

<p>Một thiết bị lưu trữ có hai ổ cứng chạy RAID sẽ chịu được <strong>một ổ chết</strong>. Ổ hỏng, thay ổ mới, dữ liệu vẫn nguyên. Nghe rất giống backup nên nhiều người dừng ở đó.</p>

<p>Nhưng RAID chép mọi thao tác sang cả hai ổ ngay lập tức, kể cả thao tác sai. Xoá nhầm một thư mục thì nó biến mất khỏi cả hai ổ cùng lúc. Mã độc tống tiền mã hoá dữ liệu thì cả hai ổ cùng bị mã hoá. Và cháy văn phòng thì cả hai ổ cùng nằm trong đám cháy đó.</p>

<p>Vụ cháy năm 2020 của công ty mình đúng là trường hợp cuối. Bao nhiêu ổ cứng cũng vô nghĩa khi chúng ở chung một chỗ.</p>

<h2 id="kho-tài-liệu-nên-dựng-thế-nào">Kho tài liệu nên dựng thế nào</h2>

<p>Đặt kho trên một thiết bị của công ty, không phải máy cá nhân của ai. Một con NAS đặt ở văn phòng là đủ cho quy mô vài chục GB mỗi năm.</p>

<p>Cấu trúc thư mục nên phẳng và đoán được, vì người tra cứu sau này có thể không phải bạn:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Chung-tu/
├── 2026/
│   ├── 01-Hoa-don-dau-vao/
│   ├── 02-Hoa-don-dau-ra/
│   ├── 03-Phieu-thu-chi/
│   ├── 04-Ngan-hang/
│   ├── 05-Luong-BHXH/
│   └── 06-Hop-dong/
└── 2025/
    └── ...
</code></pre></div></div>

<p>Năm đứng trước vì thời hạn lưu trữ tính theo năm — hết hạn thì xử lý trọn một thư mục. Số thứ tự trước tên loại chứng từ để thư mục luôn xếp đúng thứ tự thay vì sắp theo bảng chữ cái.</p>

<p>Đặt tên file theo một khuôn cố định, ví dụ <code class="language-plaintext highlighter-rouge">2026-03-15_HD-vao_CongtyABC_12500000.pdf</code>. Ngày viết dạng năm-tháng-ngày để sắp xếp theo tên là ra đúng thứ tự thời gian. Có số tiền trong tên file thì nhiều lúc khỏi phải mở ra xem.</p>

<p>Mỗi người một tài khoản riêng, đừng dùng chung một tài khoản cho cả phòng. Người nghỉ việc thì khoá tài khoản đó, kho tài liệu không suy suyển gì.</p>

<p><img src="/assets/images/2026/2026-09-04-luu-tru-chung-tu-sofsog.com02.png" alt="Hình danh sách tài khoản người dùng trên NAS, mỗi kế toán một tài khoản riêng sofsog.com" /></p>

<h2 id="ba-lớp-sao-lưu">Ba lớp sao lưu</h2>

<p>Bài học từ đám cháy nằm gọn trong mục này.</p>

<p><strong>Lớp một</strong> là bản đang dùng hằng ngày, nằm trên NAS ở văn phòng.</p>

<p><img src="/assets/images/2026/2026-09-04-luu-tru-chung-tu-sofsog.com03.png" alt="Hình máy trạm sao lưu liên tục lên NAS, báo backup hoàn tất sofsog.com" /></p>

<p><strong>Lớp hai</strong> là một ổ cứng ngoài, chép định kỳ rồi <strong>cất ở địa điểm khác</strong>. Nhà riêng, chi nhánh, két ở ngân hàng, chỗ nào cũng được miễn không cùng toà nhà với lớp một. Nếu năm 2020 công ty mình có lớp này thì bài viết đã không cần tồn tại.</p>

<p><strong>Lớp ba</strong> là một bản trên dịch vụ đám mây. Lớp này chống được cả trường hợp mất cắp cả NAS lẫn ổ ngoài.</p>

<p>Và phần quan trọng nhất mà gần như ai cũng bỏ qua: <strong>mỗi năm mở thử một bản backup ra xem</strong>. Chọn ngẫu nhiên vài file, mở lên, đọc được thì thôi. Một bản sao lưu chưa từng được thử phục hồi thì chưa phải là bản sao lưu, nó chỉ là một niềm tin.</p>

<h2 id="mười-năm-là-quãng-rất-dài">Mười năm là quãng rất dài</h2>

<p>Ổ cứng không sống được mười năm. Kế hoạch phải tính tới việc thay thiết bị giữa chừng, và chép dữ liệu sang thiết bị mới là một việc có lịch chứ không phải chuyện tính sau.</p>

<p>Định dạng file cũng vậy. Giữ chứng từ ở dạng PDF và ảnh thông thường thì mười năm sau vẫn mở được. Giữ ở định dạng riêng của một phần mềm nào đó thì phụ thuộc vào phần mềm ấy còn sống hay không.</p>

<p>Rủi ro lớn nhất lại là con người. Người dựng ra cách đặt tên và cấu trúc thư mục sẽ nghỉ việc vào một lúc nào đó, mang theo toàn bộ quy ước nằm trong đầu. Viết một trang hướng dẫn ngắn, để ngay trong thư mục gốc của kho, nói rõ thư mục nào chứa gì và tên file đọc thế nào. Một trang giấy đó có giá trị hơn nhiều so với công sức bỏ ra viết nó.</p>

<h2 id="tra-cứu-được-mới-tính-là-lưu-trữ">Tra cứu được mới tính là lưu trữ</h2>

<p>Điều kiện thứ ba của luật là tra cứu được trong suốt thời hạn. Đây là điều kiện hay bị coi nhẹ nhất.</p>

<p>Phép thử rất đơn giản: nhờ một người khác trong phòng tìm hộ một chứng từ của ba năm trước. Quá mười phút chưa ra thì kho tài liệu đó chưa đạt, dù dữ liệu vẫn còn nguyên vẹn.</p>

<p>File PDF scan nên bật nhận dạng chữ để tìm được theo nội dung bên trong chứ không chỉ theo tên file. Phần lớn máy scan văn phòng có sẵn tuỳ chọn này, chỉ là mặc định hay bị tắt.</p>

<h2 id="bài-này-không-thay-được-gì">Bài này không thay được gì</h2>

<p>Nói thẳng mấy giới hạn để bạn khỏi hiểu nhầm.</p>

<p>Đây không phải tư vấn pháp lý. Mình dẫn số điều để bạn biết đường tra, không phải để bạn trích dẫn lại.</p>

<p>Bản điện tử không thay thế được những bản gốc mà đơn vị bạn vẫn phải giữ bằng giấy. Scan xong đừng vội bỏ giấy đi.</p>

<p>Hoá đơn điện tử và chữ ký số thì mình chưa đụng tới ở đây. Hai thứ đó có quy định riêng và đủ dài để thành một bài khác.</p>

<p>Và trung thực với bạn: ở ba công ty mình đang làm, hiện trạng vẫn là mỗi nơi một mảnh — tủ hồ sơ ở kho, một phần trên Drive, dữ liệu MISA trên máy chủ nội bộ. Những gì viết ở trên là cách mình đang gom lại, chưa phải một hệ thống đã chạy trọn vẹn mười năm. Cái mình chắc chắn là bài học năm 2020: đừng để mọi bản lưu nằm chung một địa chỉ.</p>

<p>Chúc các bạn thành công.</p>

<h2 id="link-tham-khảo">Link tham khảo</h2>

<p><a href="https://luatvietnam.vn/ke-toan/luat-ke-toan-2015-101336-d1.html">https://luatvietnam.vn/ke-toan/luat-ke-toan-2015-101336-d1.html</a></p>

<p><a href="https://luatvietnam.vn/ke-toan/nghi-dinh-174-2016-nd-cp-chinh-phu-111573-d1.html">https://luatvietnam.vn/ke-toan/nghi-dinh-174-2016-nd-cp-chinh-phu-111573-d1.html</a></p>]]></content><author><name>Thành</name></author><category term="ke-toan" /><category term="server" /><category term="kế toán" /><category term="lưu trữ" /><category term="NAS" /><category term="backup" /><category term="chứng từ" /><summary type="html"><![CDATA[Luật bắt giữ chứng từ kế toán tối thiểu **10 năm**, và cho phép giữ dưới dạng điện tử nếu bảo đảm được ba điều kiện. Bài này nói về ba điều kiện đó, và vì sao một thư mục **Google Drive** của nhân viên không đáp ứng được cái nào cho tử tế.]]></summary></entry><entry><title type="html">NodeWarden hay Vaultwarden - chạy song song mấy tháng rồi mình chốt cái nào</title><link href="https://sofsog.com/server/nodewarden-hay-vaultwarden-chot-cai-nao" rel="alternate" type="text/html" title="NodeWarden hay Vaultwarden - chạy song song mấy tháng rồi mình chốt cái nào" /><published>2026-09-04T00:00:00+00:00</published><updated>2026-09-04T00:00:00+00:00</updated><id>https://sofsog.com/server/nodewarden-hay-vaultwarden-chot-cai-nao</id><content type="html" xml:base="https://sofsog.com/server/nodewarden-hay-vaultwarden-chot-cai-nao"><![CDATA[<p>Ở <a href="/server/vaultwarden-tren-nas-kho-mat-khau-cho-ca-nha">bài về Vaultwarden</a> mình viết là đang chạy song song cả hai và chưa chốt cái nào. Giờ đã chốt: mình dùng <strong>NodeWarden</strong>.</p>

<aside class="series-box" aria-label="Các bài trong series Tự dựng server tại nhà"><p class="series-box__dau">Series <a href="/series/">Tự dựng server tại nhà</a> &middot; bài 7/9 <span class="series-box__cap">Nâng cao</span></p><ol class="series-box__ds"><li><a href="/server/dung-gitea-tren-nas-dong-bo-obsidian-giua-pc-va-dien-thoai">Dựng Gitea trên NAS - "GitHub riêng" để đồng bộ Obsidian giữa PC và điện thoại</a></li><li><a href="/server/tailscale-vao-nas-tu-xa-khong-mo-port">Tailscale - vào NAS từ bất cứ đâu mà không mở port trên router</a></li><li><a href="/server/vaultwarden-tren-nas-kho-mat-khau-cho-ca-nha">Vaultwarden trên NAS - kho mật khẩu cho cả nhà, không trả phí hằng tháng</a></li><li><a href="/server/chon-nas-dau-tien-mua-dung-san-hay-tu-lap">Chọn NAS đầu tiên - mua hộp dựng sẵn hay tự lắp từ máy chủ cũ</a></li><li><a href="/server/quy-tac-3-2-1-lam-cho-that">Quy tắc 3-2-1 làm cho thật - ngồi đếm lại mới biết mình thiếu gì</a></li><li><a href="/server/privatebin-tren-nas-chia-se-text-co-mat-khau">PrivateBin trên NAS - link chia sẻ text có mật khẩu, không giới hạn 31 ngày</a></li><li class="dang-doc" aria-current="true">NodeWarden hay Vaultwarden - chạy song song mấy tháng rồi mình chốt cái nào</li><li><a href="/server/nas-het-ram-do-truoc-khi-cai-them">NAS hết RAM: zram đầy 100%, gần 1 GB tràn xuống ổ cứng</a></li><li><a href="/server/keo-154-repo-github-ve-nas-bang-gitea">Kéo 154 repo GitHub về NAS: mirror tự cập nhật bằng Gitea</a></li></ol></aside>

<p>Bài này không phải bài hướng dẫn cài. Nó là lý do chọn, đánh đổi cụ thể phải trả, và những gì mình làm để bù lại đánh đổi đó.</p>

<h2 id="vì-sao-chốt-nodewarden">Vì sao chốt NodeWarden</h2>

<p>Lý do rất đời thường: <strong>nó tiện hơn và ít lỗi vặt hơn</strong>.</p>

<p>Tiện, vì nó chạy trên Cloudflare Workers nên không cần mạng riêng. Ở đâu có Internet là dùng được, không phải nhớ bật Tailscale, không phụ thuộc con NAS ở nhà còn sống hay không.</p>

<p>Ít lỗi vặt, vì tiện ích trình duyệt của Bitwarden khi nối vào Vaultwarden thỉnh thoảng nạp lỗi. Không thường xuyên, nhưng đủ để khó chịu. Một trình quản lý mật khẩu thì phải luôn sẵn sàng, chứ mỗi lần trục trặc lại phải nghĩ xem lỗi ở đâu thì mất hết ý nghĩa.</p>

<p>Đổi lại là một phần bảo mật. Phần đó cụ thể thế nào, mình nói ngay dưới đây thay vì nói chung chung.</p>

<h2 id="hai-kiến-trúc-khác-nhau-ở-đâu">Hai kiến trúc khác nhau ở đâu</h2>

<table>
  <thead>
    <tr>
      <th> </th>
      <th>Vaultwarden</th>
      <th>NodeWarden</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Chạy ở đâu</td>
      <td>Docker trên NAS nhà mình</td>
      <td>Cloudflare Workers</td>
    </tr>
    <tr>
      <td>Dữ liệu nằm ở</td>
      <td>ổ cứng của mình</td>
      <td>Cloudflare D1 và R2</td>
    </tr>
    <tr>
      <td>Truy cập từ ngoài</td>
      <td>phải qua Tailscale</td>
      <td>mọi nơi có Internet</td>
    </tr>
    <tr>
      <td>Máy chủ chết thì</td>
      <td>tự mình sửa</td>
      <td>Cloudflare lo</td>
    </tr>
    <tr>
      <td>Thuật toán bảo vệ khoá</td>
      <td>đổi được sang Argon2id</td>
      <td><strong>khoá cứng PBKDF2</strong></td>
    </tr>
    <tr>
      <td>Chi phí</td>
      <td>tiền điện NAS</td>
      <td>miễn phí ở quy mô cá nhân</td>
    </tr>
  </tbody>
</table>

<p>Dòng áp chót là đánh đổi lớn nhất, và mình sẽ nói kỹ.</p>

<h2 id="dự-án-này-có-đáng-tin-không">Dự án này có đáng tin không</h2>

<p>Trước khi bàn đánh đổi kỹ thuật, cần nhìn thẳng vào chỗ này: bạn đang giao toàn bộ mật khẩu cho một dự án mã nguồn mở của một người lạ.</p>

<p><img src="/assets/images/2026/2026-09-04-nodewarden-vaultwarden-sofsog.com01.png" alt="Hình trang giới thiệu dự án NodeWarden sofsog.com" /></p>

<p>Dự án phát hành theo giấy phép LGPL-3.0, bản mình dùng là 1.8.0. Nhưng dòng đáng chú ý nhất nằm ở phần cuối trang giới thiệu: chính tác giả ghi rõ đây là dự án <strong>cho mục đích học tập và thảo luận</strong>, khuyên người dùng sao lưu vault thường xuyên, và nói rõ dự án không liên kết với Bitwarden.</p>

<p>Với một trình quản lý mật khẩu thì lời tự bạch đó không phải chuyện nhỏ. Nó nghĩa là không có ai cam kết bảo hành, và không có đội ngũ nào chịu trách nhiệm nếu hỏng.</p>

<p>Mặt khác, dự án rõ ràng còn sống:</p>

<p><img src="/assets/images/2026/2026-09-04-nodewarden-vaultwarden-sofsog.com02.png" alt="Hình biểu đồ số sao GitHub của dự án NodeWarden theo thời gian sofsog.com" /></p>

<p>Khoảng 3.500 sao sau bảy tháng, đường cong vẫn đi lên đều. Số sao chỉ đo mức chú ý chứ <strong>không đo mức an toàn</strong>, vì không ai kiểm định bảo mật một dự án bằng cách đếm sao. Nhưng nó cho biết dự án đang được cập nhật, lỗi báo lên còn có người đọc, và mình không phải người duy nhất dùng.</p>

<p>Sở dĩ mình vẫn dùng nó không phải vì tin tưởng sẵn, mà vì đã đọc mã nguồn ở đúng những chỗ nhạy cảm, đã đo lại các cơ chế bảo vệ, và đã dựng ba lớp sao lưu để nếu dự án chết thì vẫn lấy được dữ liệu ra. Mấy phần dưới đây là những gì tìm thấy khi làm việc đó.</p>

<h2 id="đánh-đổi-cụ-thể-phải-trả">Đánh đổi cụ thể phải trả</h2>

<h3 id="kdf-bị-khoá-cứng-không-nâng-cấp-được">KDF bị khoá cứng, không nâng cấp được</h3>

<p>NodeWarden dùng <strong>PBKDF2 600.000 vòng</strong> và không cho đổi sang Argon2id, dù hàm kiểm tra tham số trong mã nguồn có hỗ trợ Argon2id.</p>

<p>Đi tìm chỗ chặn thì thấy hai lớp độc lập. Endpoint đổi KDF trả về thông báo không hỗ trợ. Đường đổi qua endpoint mật khẩu cũng bị chặn riêng. Tạo tài khoản mới cũng không lách được, vì giao diện web ghi cứng loại KDF, và phần mã hoá phía trình duyệt chỉ có PBKDF2 chứ không có Argon2 — ép qua API thì chính giao diện đó không mở khoá được tài khoản vừa tạo.</p>

<p>Hệ quả cần hiểu rõ: <strong>chống bẻ khoá ngoại tuyến giờ chỉ còn dựa vào độ mạnh của mật khẩu chính</strong>. Không có lớp bù nào khác. Argon2id chống được tấn công bằng GPU tốt hơn PBKDF2 nhiều, và ở đây mình không có lựa chọn đó.</p>

<h3 id="tệp-sao-lưu-không-được-mã-hoá">Tệp sao lưu không được mã hoá</h3>

<p>Đây là điều mình chỉ biết sau khi đọc mã nguồn phần tạo bản sao lưu, và nó quan trọng hơn cả mục trên.</p>

<p>Bản backup là tệp ZIP nén kiểu lưu trữ thuần, bên trong có một tệp JSON chứa nguyên các dòng cơ sở dữ liệu, gồm cả <strong>mã bí mật của xác thực hai lớp ở dạng đọc được</strong>.</p>

<p>Nghĩa là ai lấy được tệp backup thì lớp xác thực hai lớp coi như vô hiệu, và nội dung kho chỉ còn được bảo vệ bằng độ mạnh mật khẩu chính. Ba việc bắt buộc phải làm theo:</p>

<p>Thư mục chứa backup phải giới hạn quyền chặt, và <strong>đừng để nó lọt vào phạm vi đồng bộ của Synology Drive</strong> hay bất kỳ thư mục chia sẻ nào mở ra ngoài.</p>

<p>Khi mở tệp zip ra kiểm tra thì chỉ xem tệp kê khai, đừng mở tệp dữ liệu.</p>

<p>Và đừng bao giờ gửi tệp backup qua chat hay email như một tệp bình thường.</p>

<h3 id="hai-chỗ-còn-lại">Hai chỗ còn lại</h3>

<p>Chính sách bảo mật nội dung của ứng dụng vẫn cho phép mã nội tuyến, làm nó mất phần lớn tác dụng chống tấn công chèn mã. Không sửa được nếu không tự chỉnh mã nguồn.</p>

<p>Và tên miền mình dùng là <strong>miền miễn phí</strong>. Nếu bị thu hồi hoặc tài khoản đăng ký bị chiếm, kẻ tấn công dựng được trang đăng nhập giả ngay trên chính tên miền đó — mật khẩu mạnh không cứu được tình huống này. Đây là chỗ mình sẽ đổi sang tên miền trả phí.</p>

<h2 id="những-gì-đã-làm-để-bù-lại">Những gì đã làm để bù lại</h2>

<p>Mấy việc dưới đây là thứ khiến mình yên tâm chuyển hẳn sang NodeWarden.</p>

<h3 id="ẩn-toàn-bộ-giao-diện-web">Ẩn toàn bộ giao diện web</h3>

<p>Biến <code class="language-plaintext highlighter-rouge">HIDE_WEB_VAULT</code> bật lên thì mọi đường dẫn giao diện web trả về <code class="language-plaintext highlighter-rouge">404</code>, chỉ còn phần API cho tiện ích trình duyệt và ứng dụng điện thoại. Kiểm chứng bằng cách gọi thử: trang chủ, trang cài đặt, tệp manifest đều <code class="language-plaintext highlighter-rouge">404</code>, còn các đường API vẫn trả về bình thường.</p>

<p>Kẻ tấn công dò trúng tên miền cũng không có trang đăng nhập nào để thử mật khẩu.</p>

<p><strong>Phải đặt biến này kiểu <code class="language-plaintext highlighter-rouge">Secret</code>, không phải <code class="language-plaintext highlighter-rouge">Text</code>.</strong> Lý do rất dễ sập bẫy: tệp cấu hình của Worker không khai báo khối biến môi trường, mà lệnh triển khai sẽ ghi đè biến của Worker theo đúng tệp cấu hình đó. Biến kiểu văn bản thêm tay trên bảng điều khiển sẽ <strong>bị xoá ở lần triển khai kế tiếp</strong>, và giao diện web lặng lẽ hiện lại mà không ai báo. Biến kiểu bí mật thì lệnh triển khai không đụng tới.</p>

<p>Cũng đừng sửa tệp cấu hình trong bản sao mã nguồn để thêm khối đó. Bản sao đang sạch so với gốc, sửa vào là mất khả năng cập nhật nhanh khi có bản mới.</p>

<p>Đổi lại, khi đang ẩn thì mất Backup Center, Log Center, quản lý thiết bị và đổi mật khẩu qua web. Việc sao lưu tự động vẫn chạy vì nó là tác vụ định kỳ của Worker, không liên quan giao diện.</p>

<h3 id="bật-hsts">Bật HSTS</h3>

<p>Đặt ở Cloudflare, thời hạn sáu tháng, áp cho cả tên miền con. <strong>Tắt Preload</strong>, vì đây là miền miễn phí, mà vào danh sách preload là một cam kết rất khó gỡ về sau.</p>

<p>Bộ tiêu đề bảo mật sau khi lên phiên bản mới gồm HSTS, chính sách chặn nhúng khung, chặn đoán kiểu tệp, chính sách giới thiệu nguồn, và thẻ chặn công cụ tìm kiếm lập chỉ mục.</p>

<p>Đáng chú ý: bản cũ <strong>không có tiêu đề bảo mật nào</strong> — chính sách bảo mật nội dung chỉ nằm trong thẻ meta, mà theo chuẩn thì chỉ thị chặn nhúng khung bị bỏ qua khi đặt ở đó. Tức là trang đăng nhập có thể bị nhúng vào khung của trang khác. Chỉ riêng việc cập nhật phiên bản đã đóng lỗ này.</p>

<h3 id="giới-hạn-tần-suất-đã-có-sẵn-và-mình-đã-đo">Giới hạn tần suất đã có sẵn, và mình đã đo</h3>

<p>Mình không tin vào tài liệu, nên bắn thử 35 yêu cầu liên tiếp vào đường dẫn kiểm tra tài khoản. Kết quả: đúng <strong>30 lần trả về <code class="language-plaintext highlighter-rouge">200</code> rồi 5 lần trả về <code class="language-plaintext highlighter-rouge">429</code></strong>.</p>

<p>Cấu hình trong mã nguồn là 30 yêu cầu mỗi phút cho các đường nhạy cảm, 120 cho đọc, 200 cho API đã xác thực, và <strong>sai mật khẩu 10 lần thì khoá 2 phút</strong>.</p>

<p>Có một bài viết tiếng Việt hồi tháng 4 chê NodeWarden thiếu giới hạn tần suất. Thông tin đó đã lỗi thời.</p>

<h3 id="đóng-đăng-ký-và-khoá-tài-khoản-github">Đóng đăng ký và khoá tài khoản GitHub</h3>

<p>Sau người dùng đầu tiên, mọi tài khoản mới đều phải có mã mời. Đây là mặc định của phần mềm chứ không phải mình cấu hình.</p>

<p>Còn tài khoản GitHub thì <strong>bắt buộc bật xác thực hai lớp</strong>. Lý do: Worker được xây từ bản sao mã nguồn của mình, nên ai chiếm được tài khoản GitHub là đẩy được mã độc vào trình duyệt đang mở kho mật khẩu. Mình cũng giữ cách đồng bộ thủ công và <strong>không bật tự động đồng bộ</strong>, để không có đường nào tự chạy mà mình không nhìn thấy.</p>

<h2 id="chuỗi-sao-lưu-ba-lớp">Chuỗi sao lưu ba lớp</h2>

<table>
  <thead>
    <tr>
      <th>Lớp</th>
      <th>Nơi lưu</th>
      <th>Cơ chế</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Bản chính</td>
      <td>Cloudflare D1</td>
      <td>Worker tự chạy</td>
    </tr>
    <tr>
      <td>Ngoài nhà</td>
      <td>Koofr qua WebDAV</td>
      <td>NodeWarden tự đẩy, 24 giờ một lần, giữ 30 bản</td>
    </tr>
    <tr>
      <td>Tại chỗ</td>
      <td>NAS</td>
      <td>Cloud Sync tự kéo về, giữ cả bản Koofr đã dọn</td>
    </tr>
  </tbody>
</table>

<p>Trên NAS hiện có 10 tệp, mỗi tệp đúng 8.955.540 byte. Dung lượng giống hệt nhau từng ngày cho thấy đây là bản kết xuất toàn bộ mỗi lần, không phải sao lưu tăng dần. Khác hẳn cách restic làm ở bài Vaultwarden, nơi mỗi lần chỉ ghi thêm vài chục KB.</p>

<h3 id="vì-sao-phải-vòng-qua-koofr">Vì sao phải vòng qua Koofr</h3>

<p>Câu hỏi hợp lý là sao không đẩy thẳng từ Worker về NAS.</p>

<p>Vì tác vụ định kỳ của Worker chạy trên hạ tầng biên của Cloudflare, nó chỉ gọi được những địa chỉ công khai. NAS của mình chỉ có địa chỉ trong mạng Tailscale nên Worker không nhìn thấy.</p>

<p>Muốn đẩy thẳng thì phải mở dịch vụ chia sẻ tệp của NAS ra Internet. Mà phần cấu hình đích trong NodeWarden chỉ nhận địa chỉ, tên đăng nhập và mật khẩu — <strong>không gửi được tiêu đề tuỳ chỉnh</strong>, nên không khoá đường hầm đó bằng mã dịch vụ của Cloudflare Access được.</p>

<p>Nên mình chọn hướng ngược lại: <strong>để NAS kéo về</strong>. Toàn bộ kết nối là đi ra, không mở thêm cổng nào. Đúng nguyên tắc đã dùng cho <a href="/server/tailscale-vao-nas-tu-xa-khong-mo-port">Tailscale</a> và <a href="/server/privatebin-tren-nas-chia-se-text-co-mat-khau">PrivateBin</a>.</p>

<p>Phần đồng bộ trên NAS phải đặt <strong>một chiều, chỉ tải bản mới về</strong>. Để hai chiều thì có ngày NAS xoá nhầm rồi đẩy lệnh xoá ngược lên, mất luôn bản gốc. Nhớ tick thêm tuỳ chọn không xoá tệp ở đích khi nguồn đã xoá. Nhờ vậy bản trên NAS thành kho lưu trữ dài hạn chứ không chỉ là bản sao.</p>

<h2 id="kiểm-tra-backup-khi-giao-diện-web-đang-ẩn">Kiểm tra backup khi giao diện web đang ẩn</h2>

<p>Vì đã ẩn giao diện nên không vào Backup Center được. Kiểm tra từ NAS qua SSH:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">ls</span> <span class="nt">-la</span> /volume1/.../Backup/nodewarden
unzip <span class="nt">-p</span> /volume1/.../Backup/nodewarden/&lt;ten-file&gt;.zip manifest.json
</code></pre></div></div>

<p>Tệp kê khai cho biết phiên bản ứng dụng, thời điểm kết xuất và số lượng bản ghi từng bảng để đối chiếu. Lần kiểm ngày 27/08/2026: phiên bản 1.8.0, 4.598 mục mật khẩu, 81 thư mục, 0 tệp đính kèm.</p>

<p>Nhắc lại vì quan trọng: <strong>chỉ mở tệp kê khai, đừng mở tệp dữ liệu</strong>.</p>

<h2 id="phục-hồi-là-ghi-đè-toàn-bộ">Phục hồi là ghi đè toàn bộ</h2>

<p>Chỗ này phải biết trước khi cần dùng.</p>

<p>Đọc mã nguồn phần nhập dữ liệu thì chỉ có hai chế độ: mặc định chỉ chạy được trên một hệ thống trống, còn chế độ thay thế thì <strong>xoá sạch toàn bộ các bảng rồi nạp lại</strong>. Không có chế độ gộp. Mọi mục thêm vào sau ngày sao lưu sẽ mất.</p>

<p>Sau khi phục hồi, mật khẩu chính quay về mật khẩu tại thời điểm sao lưu, dấu bảo mật đổi nên <strong>văng đăng nhập trên mọi thiết bị</strong>, và mã xác thực hai lớp quay về giá trị cũ.</p>

<p>Bảng dữ liệu của tính năng gửi tệp tạm <strong>không nằm trong bản sao lưu</strong>.</p>

<p>Mình đã thử phục hồi thật trên chính tài khoản đang dùng ngày 27/08/2026 và thành công. Nói lại lần nữa điều đã viết ở <a href="/server/quy-tac-3-2-1-lam-cho-that">bài 3-2-1</a>: một bản sao lưu chưa từng được mở ra thử thì chưa phải bản sao lưu.</p>

<h2 id="vậy-bạn-nên-chọn-cái-nào">Vậy bạn nên chọn cái nào</h2>

<p>Không né bằng câu mỗi bên có cái hay riêng.</p>

<p><strong>Chọn Vaultwarden</strong> nếu bạn coi trọng việc dữ liệu nằm trên phần cứng mình cầm được, và chấp nhận phải bật mạng riêng mỗi lần dùng. Nó cũng cho bạn đổi sang thuật toán bảo vệ khoá mạnh hơn, thứ NodeWarden không có.</p>

<p><strong>Chọn NodeWarden</strong> nếu bạn muốn dùng ở mọi nơi mà không phải nghĩ, và chấp nhận dữ liệu nằm trên hạ tầng của bên khác cùng thuật toán bảo vệ khoá không nâng cấp được.</p>

<p>Mình chọn cái thứ hai, nhưng chỉ sau khi đã ẩn giao diện web, bật HSTS, đo lại giới hạn tần suất, khoá tài khoản GitHub bằng xác thực hai lớp, và dựng đủ ba lớp sao lưu. Nếu bỏ qua mấy bước đó thì đánh đổi bảo mật sẽ lớn hơn nhiều so với những gì mình mô tả ở đây.</p>

<p>Và dù chọn bên nào, <strong>mật khẩu chính phải thật mạnh</strong>. Với NodeWarden thì nó gần như là lớp phòng thủ cuối cùng.</p>

<p>Chúc các bạn thành công.</p>

<h2 id="link-tham-khảo">Link tham khảo</h2>

<p><a href="https://github.com/shuaiplus/nodewarden">https://github.com/shuaiplus/nodewarden</a></p>

<p><a href="https://github.com/dani-garcia/vaultwarden">https://github.com/dani-garcia/vaultwarden</a></p>

<p><a href="https://developers.cloudflare.com/workers/configuration/secrets/">https://developers.cloudflare.com/workers/configuration/secrets/</a></p>

<p><a href="https://bitwarden.com/help/kdf-algorithms/">https://bitwarden.com/help/kdf-algorithms/</a></p>]]></content><author><name>Thành</name></author><category term="server" /><category term="thu-thuat-chung" /><category term="NodeWarden" /><category term="Vaultwarden" /><category term="Bitwarden" /><category term="Cloudflare Workers" /><category term="bảo mật" /><summary type="html"><![CDATA[Bài Vaultwarden trước mình hẹn sẽ viết tiếp sau khi có kết luận. Giờ có rồi: mình chốt **NodeWarden**. Bài này nói rõ đánh đổi bảo mật là gì, và những gì mình đã làm để bù lại.]]></summary></entry></feed>