Backup

Tài liệu

Cách hệ thống hoạt động và cách dùng nó. Mọi con số dưới đây là giá trị đang chạy thật, không phải ví dụ.

Sản phẩm này giải quyết gì

Đây là control plane cho việc sao lưu: một chỗ để khai chính sách, phát xuống nhiều máy, và trả lời được câu hỏi khó nhất của mọi hệ thống backup — đêm qua máy nào KHÔNG sao lưu được?

Chạy được một script rclone trên từng máy là chuyện dễ. Cái khó là sau sáu tháng, khi có 40 máy, không ai còn biết máy nào đang chạy bản script nào, máy nào đã im lặng ba tuần, và cảnh báo của máy nào đang gửi vào một nhóm chat không còn ai đọc.

Nguyên tắc nền

Máy được sao lưu không bao giờ cầm khoá xoá của kho lưu trữ. Agent chỉ nhận URL ký sẵn cho đúng một tệp, sống 30 phút. Một máy bị chiếm quyền không xoá được bản backup của chính nó — đó là điểm khác biệt so với việc phát access key cho từng máy.

Ba thành phần

Server
Go + PostgreSQL

Giữ chính sách, cấp URL ký sẵn, gom nhật ký, phát cảnh báo. Là nơi duy nhất cầm khoá kho lưu trữ.

Agent
dịch vụ nền trên từng máy

Quét thư mục, đẩy tệp thẳng lên kho lưu trữ, báo kết quả về. Không mở cổng nào — luôn là bên gọi đi.

Web
chính là trang bạn đang xem

Khai cấu hình, duyệt máy mới, đọc cảnh báo và nhật ký.

Một vòng chạy đầy đủ:

  1. 1.Agent gọi về server (agent luôn chủ động, server không gọi ngược)
  2. 2.Server trả config đã resolve + lệnh đang chờ
  3. 3.Tới giờ theo lịch, agent quét thư mục nguồn
  4. 4.Với tệp đã đổi, agent xin URL ký sẵn cho từng tệp
  5. 5.Agent PUT thẳng lên kho lưu trữ — dữ liệu KHÔNG đi qua server
  6. 6.Agent xác nhận, server cập nhật chỉ mục và trạng thái

Dữ liệu không đi qua server là chủ ý: một server 2 vCPU không thể làm trạm trung chuyển cho 40 máy cùng đẩy vài trăm GB.

Bắt đầu trong 5 bước

  1. 1
    Đặt khoá mã hoá cho server

    Không có STORAGE_KEY thì server từ chối lưu khoá kho lưu trữ và bot token — nó không ghi plaintext làm phương án thay thế.

    STORAGE_KEY=$(openssl rand -base64 32)

    Mất khoá này là mất khả năng giải mã mọi secret đã lưu. Cất cùng chỗ với mật khẩu database.

  2. 2
    Khai kho lưu trữ

    Cấu hình → Kho lưu trữ. Khai một hồ sơ storage — endpoint, region, bucket khai một lần rồi chọn lại ở mọi lớp, khỏi gõ lại ở từng nơi.

    Khoá truy cập nằm bên dưới hồ sơ, được mã hoá AES-256-GCM trước khi ghi và không API nào đọc ngược ra. Chỉ còn lại vân tay 4 byte để đối chiếu đúng khoá.

  3. 3
    Khai chính sách mặc định

    Cấu hình → Chính sách mặc định là lớp global, áp cho mọi máy: thư mục nguồn, loại trừ, lịch chạy, kho lưu trữ đích.

  4. 4
    Cài agent lên máy cần sao lưu

    Trước hết lấy mã cài đặt ở Cấu hình → Nhóm máy → chọn nhóm → Mã cài đặt. Máy cài bằng mã của nhóm nào sẽ vào thẳng nhóm đó và nhận cấu hình của nhóm ngay từ lần sync đầu. Một mã dùng chung cho cả đợt — chọn số máy, hoặc để không giới hạn. Mọi máy dùng cùng một mã sẽ vào cùng một nhóm, nên đây cũng là cách gán sẵn một cụm máy vào cùng chính sách.

    chỉ hiện đúng một lần lúc tạo — server chỉ giữ bản băm. Màn hình đó cho sẵn lệnh cài đã ghép đủ địa chỉ server và mã, chép dán thẳng được.

    Giải nén gói cài rồi chạy bằng quyền quản trị. Linux (cần systemd):

    tar xzf backup-agent-<ver>-linux-amd64.tar.gz
    cd backup-agent-<ver>-linux-amd64
    sudo ./install.sh --server https://backup.noi-bo --token <enroll-token>

    Windows — mở PowerShell bằng Run as Administrator:

    .\install.ps1 -Server https://backup.noi-bo -Token <enroll-token>

    Thư mục cần sao lưu nằm trên NAS thì đọc thêm Nguồn trên ổ mạng trước khi cài — có một cái bẫy riêng của Windows ở đó.

    Agent rơi vào trạng thái Chờ duyệt. Máy chờ duyệt không nhận config thật, không nhận khoá kho lưu trữ, không nhận bot token — cắm nhầm một máy lạ vào mạng không làm rò rỉ gì.

    Nâng cấp: chạy lại chính install script đó

    Nó tự dừng service, thay tệp chạy, rồi chạy lại — giữ nguyên danh tính máy và chỉ mục tệp đã sao lưu, nên lượt kế tiếp vẫn chỉ đẩy phần thay đổi. Đừng gỡ ra cài lại: gỡ kèm --purge sẽ xoá danh tính, máy thành máy mới trên danh sách và phải đẩy lại từ đầu.
  5. 5
    Duyệt máy và gắn kênh thông báo

    Agent → chip Chờ duyệt → menu cuối dòng → Duyệt máy này. Sau đó tạo ít nhất một kênh ở Cấu hình → Thông báo và bấm Gửi thử.

    Đừng bỏ bước Gửi thử

    Không bấm thử thì lần đầu biết kênh cấu hình sai sẽ đúng vào lúc có sự cố thật.

Cấu hình phân lớp

Ba lớp, lớp sau đè lớp trước:

  1. 1.global — mọi máy
  2. 2.group — một nhóm máy
  3. 3.agent — riêng một máy

Chỉ những mục bật công tắc mới được khai ở lớp dưới. Mục không bật rơi xuống lớp trên — vì vậy không có khái niệm “giá trị mặc định” ở lớp agent.

Với các trường dạng danh sách (nguồn, loại trừ), bắt buộc khai mode:

modenghĩa
replaceBỏ hẳn danh sách của lớp trên, dùng danh sách này
appendNối thêm vào danh sách của lớp trên

Bắt khai rõ vì suy đoán ngầm ở đây rất tốn: một lớp group tưởng là append nhưng chạy thành replace sẽ âm thầm ngừng sao lưu mọi thư mục khai ở global.

Hai loại hash

hashgồm gìdùng để
config_hashToàn bộ config, kể cả đích lưu trữ (chứa id máy)Agent biết config có đổi không
policy_hashPhần không phụ thuộc máySo hai máy có cùng chính sách hay không

config_hash luôn khác nhau giữa các máy vì đích lưu trữ có id máy trong đó — nên nó không trả lời được câu “hai máy này có cùng chính sách không”. Đó là lý do có hash thứ hai.

Nhóm máy & mã cài đặt

Nhóm là lớp group ở trên. Nó tồn tại vì máy Windows và máy Linux gần như không bao giờ dùng chung được thư mục nguồn — mà khai riêng cho từng máy thì tới máy thứ mười là không ai theo nổi.

Cấu hình → Nhóm máy. Mỗi nhóm gom ba thứ vào cùng một chỗ:

Chính sách của nhómNguồn, loại trừ, lịch, đích — đè lên lớp global
Mã cài đặtMáy cài bằng mã của nhóm vào thẳng nhóm đó
Danh sách máy đang thuộc nhómChuyển máy sang nhóm khác ngay tại đây

Nhóm default không xoá được, và nhóm còn máy cũng không xoá được — xoá được thì những máy đó sẽ lặng lẽ rơi về chính sách global, thường là một chính sách không hợp với chúng.

Gắn máy đã cài vào nhóm

Agent → menu trên thẻ máy → Chuyển nhóm. Máy nhận chính sách mới ở lần gọi về kế tiếp, không cần cài lại và không mất chỉ mục tệp đã sao lưu.

Mã cài đặt

Một mã dùng được cho nhiều máy — cài cả một cụm bằng đúng một dòng lệnh, và cả cụm vào cùng một nhóm.

tuỳ chọnmặc địnhý nghĩa
max_uses1Số máy dùng được. Đặt 0 = không giới hạn
ttl_hours72Hạn dùng, tối đa 720 (30 ngày)
allowed_cidrstrốngChỉ nhận enroll từ dải IP này. Trống = từ đâu cũng được
auto_approvetắtMáy vào thẳng trạng thái đang chạy, không cần ai duyệt

Tự duyệt bắt buộc phải kèm dải IP

Hệ thống từ chối tạo mã vừa tự duyệt vừa không giới hạn IP. Một mã như vậy rò ra ngoài là bất kỳ ai cũng tạo được một máy đã duyệt — tức là một máy nhận đủ config thật, khoá kho lưu trữ và bot token.

chỉ hiện đúng một lần lúc tạo; server chỉ giữ bản băm. Mất thì thu hồi rồi tạo mã khác. Thu hồi có hiệu lực ngay, nhưng không đụng tới máy đã cài bằng mã đó — chúng đã có token riêng.

Hết lượt dùng thì lần enroll tiếp theo bị từ chối kèm lý do rõ ràng, chứ không báo “mã sai” — nhầm hai chuyện đó khiến người cài đi tìm lại mã trong khi mã vẫn đúng.

Hồ sơ kho lưu trữ

Endpoint, region, bucket, path-style… khai một lần thành một hồ sơ, rồi ở global / nhóm / máy chỉ việc chọn ra từ danh sách. Sửa endpoint một chỗ là mọi lớp đang trỏ tới đó đổi theo.

Cấu hình → Kho lưu trữHồ sơ. Ở trình soạn chính sách, nút Chọn hồ sơ mở danh sách đã tạo sẵn; vẫn khai tay được từng trường nếu một máy cần đi hướng khác.

Hồ sơ trỏ tới khoá, không chứa khoá

Hồ sơ giữ credential_id. Đổi khoá truy cập thì sửa đúng một bản ghi khoá, không phải đi tìm lại mọi nơi đã dán nó vào.

prefix cố ý không nằm trong hồ sơ: nó là cách chia không gian tên giữa các nhóm máy, nên nó thuộc về lớp chính sách chứ không thuộc về cái kho.

Trước khi xoá một hồ sơ, cột Đang dùng cho biết bao nhiêu lớp đang trỏ tới nó. Xoá một hồ sơ đang dùng là làm những máy đó mất đích lưu trữ.

Ngưỡng multipart

Mặc định tệp trên 5 GiB mới chia mảnh. Hạ ngưỡng khi kho lưu trữ nằm sau một lớp có giới hạn kích thước request.

Kho lưu trữ xuất qua Cloudflare: đặt 90

Cloudflare chặn thân request ở 100 MB trên gói Free/Pro. Để nguyên mặc định thì mọi tệp trên 100 MB đều hỏng với lỗi 413 — một mã lỗi mà nhìn vào không đoán ra là do CDN chứ không phải do kho lưu trữ.

Ghi thẳng vào ổ mạng thay vì S3

Provider local ghi thẳng vào một đường dẫn đã mount: NFS, SMB/CIFS, iSCSI hay một ổ rời đều dùng chung đường này, vì sau khi mount cả ba đều chỉ là một thư mục. Việc mount thuộc về hệ điều hành (fstab, autofs), không thuộc về agent.

trườngý nghĩa
pathThư mục đích, tuyệt đối. vd /mnt/nas-backup hoặc \\nas\backup
require_mountTừ chối ghi nếu đường dẫn chưa được mount. Bật cho mọi đích trên ổ mạng

Mất đi lớp bảo vệ quan trọng nhất

Với S3, máy được sao lưu chỉ cầm URL ký sẵn cho đúng một tệp nên nó không xoá được backup của chính nó. Ghi vào một share ghi được thì điều đó không còn đúng: ransomware trên máy này với tới được thư mục đích. Bù lại phải dựa vào phía NAS — snapshot, hoặc export chỉ-cho-thêm.

Thư mục nguồn & loại trừ

ID nguồn phải ổn định

Object nằm ở <prefix><id nguồn>/…. Đổi id là cắt đứt cả lịch sử lẫn liên kết tới dữ liệu đã lưu — đổi đường dẫn thì không sao, đổi id thì mất.

Đường dẫn phải tuyệt đối. Các cờ trên từng nguồn:

cờkhi bật
recursiveQuét cả cây thư mục con, không chỉ tầng đầu
require_mountChưa mount là LỖI, không phải “quét được 0 tệp”. Bật cho mọi nguồn nằm trên ổ mạng
stay_on_filesystemKhông vượt sang filesystem khác. Thiếu nó, nguồn “/” đệ quy sẽ đi thẳng vào ổ NFS 10TB
follow_symlinksĐi theo symlink thư mục (luôn có chống vòng lặp)
max_file_size_mbBỏ qua tệp lớn hơn ngưỡng, và đếm chúng vào báo cáo

require_mount là cờ quan trọng nhất ở đây

Ổ mạng chưa mount trông y hệt một thư mục rỗng. Không bật cờ này thì hệ thống sẽ báo “sao lưu thành công” mỗi đêm trong khi thật ra không có tệp nào được lưu.

Quy tắc loại trừ

patternkhớp
/var/tmpNeo ở gốc — chỉ đúng đường dẫn đó
node_modulesKhớp ở mọi độ sâu
*.tmpTheo tên tệp, mọi độ sâu

Nguồn trên ổ mạng (NAS, SMB)

Thư mục cần sao lưu nằm trên NAS chứ không nằm trên đĩa của máy là chuyện thường. Agent đọc được, không cần cấu hình gì thêm về giao thức — nhưng trên Windows có một cái bẫy khiến gần như ai cũng vấp đúng một lần.

Luôn khai bằng đường dẫn UNC

\\nas01\ketoan\du-lieuĐúng
X:\du-lieuSai — agent sẽ không bao giờ thấy

Ổ đã ánh xạ (X:) thuộc về phiên đăng nhập của người dùng. Agent chạy như một service ở phiên khác, nên nó không thấy ổ đó dù Explorer của bạn vẫn thấy. Triệu chứng là “The system cannot find the path specified” trên một đường dẫn mở bằng tay vẫn vào được.

“Mở Z: bằng tay vẫn vào được” không chứng minh gì

Quyền đó thuộc về phiên đăng nhập của bạn, không thuộc về máy. Service chạy bằng một danh tính khác và không thừa hưởng gì từ phiên của bạn — kể cả mật khẩu bạn đã gõ lúc ánh xạ ổ. Đây là lý do một máy “rõ ràng có quyền truy cập” vẫn báo sai mật khẩu.

LocalSystem không đọc được NAS đứng riêng — không có cách lập trình nào vòng qua

Cài mặc định thì service chạy dưới LocalSystem, và Windows không cho một tiến trình LocalSystem xác thực với SMB bằng tài khoản khác. Đã thử cả ba đường và cả ba đều dừng ở lỗi 1312 (a specified logon session does not exist):
cáchkết quả
WNetAddConnection21312
NetUseAdd1312 — đây là thứ lệnh net use gọi
CredWrite / cmdkeyGhi được credential, nhưng SMB dùng nó vẫn 1312
Rào không nằm ở chỗ lưu thông tin đăng nhập mà ở chỗ LSA từ chối tạo phiên đăng nhập mạng cho LocalSystem bằng danh tính của người khác. Cách duy nhất là đổi danh tính của chính service — phần ngay dưới.

Chọn cách theo loại NAS

Service phải có danh tính của riêng nó được NAS chấp nhận. Cách làm khác hẳn nhau tuỳ NAS có tham gia domain hay không:

NAScách cấp quyền cho service
Tham gia domain (Windows Server, NAS đã join AD)Cấp quyền đọc cho TÀI KHOẢN MÁY — không sinh ra mật khẩu nào
Đứng riêng: Synology, TrueNAS, Samba, NAS gọi bằng IP trầnTài khoản Windows cục bộ TRÙNG tên và mật khẩu với user trên NAS, rồi chạy service bằng tài khoản đó

NAS trong domain — không mật khẩu nào cả

Để nguyên cách cài mặc định. Service chạy bằng LocalSystem, và khi ra mạng nó xác thực với SMB bằng tài khoản máy:

CONGTY\TENMAY$        ← dấu $ ở cuối là bắt buộc

Cấp cho tài khoản đó quyền chỉ đọc trên share nguồn, ở phía NAS. Hết. Không có mật khẩu nào được sinh ra, nên cũng không có mật khẩu nào để lộ, để hết hạn, hay để đi đổi trên ba mươi máy.

Script cài in thẳng tên tài khoản máy ra màn hình sau khi cài xong, vì cái tên đó không hiển nhiên và đoán sai thì người ta quay sang dùng tài khoản admin cho xong chuyện.

NAS đứng riêng — khớp tên và mật khẩu

NAS không tham gia domain không hiểu tài khoản máy, nên cách trên không dùng được. Nó chỉ có danh sách user của riêng nó. Windows xác thực với share bằng tên và mật khẩu của tài khoản đang chạy service, nên cách nối hai bên lại là cho chúng trùng nhau:

  1. 1.Trên NAS: tạo (hoặc dùng lại) một user chỉ có quyền ĐỌC trên share nguồn
  2. 2.Trên máy Windows: tạo một tài khoản cục bộ TRÙNG cả tên lẫn mật khẩu với user đó
  3. 3.Cài agent với -ServiceUser ".\ten-do" -ServicePassword "..."
.\install.ps1 -Server https://backup.noi-bo -Token <token> `
    -ServiceUser ".\svc-backup" -ServicePassword "..."

.\ ở đầu nghĩa là tài khoản cục bộ của máy này. Mật khẩu hai bên lệch nhau là hỏng, kể cả khi tên vẫn trùng — nên khi đổi mật khẩu thì phải đổi cả hai chỗ.

Tài khoản dịch vụ của domain

Khi cả máy lẫn NAS đều trong domain và bạn muốn một danh tính riêng:

.\install.ps1 -Server https://backup.noi-bo -Token <token> `
    -ServiceUser "CONGTY\svc-backup" -ServicePassword "..."

Tài khoản đó cần đúng ba thứ, và không cần là administrator:

  • quyền Log on as a service trên máy này
  • quyền đọc trên share nguồn
  • toàn quyền trên C:\ProgramData\BackupAgent — script tự cấp

Thiếu “Log on as a service” = lỗi 1069

Windows chỉ nói logon failure, nên người cài sẽ đi kiểm lại mật khẩu — mật khẩu hoàn toàn đúng. Script cài nhận ra trường hợp này và in sẵn đường đi trong secpol.msc.

Đừng cho agent quyền ghi lên share nguồn

Agent chỉ đọc nguồn rồi đẩy lên kho lưu trữ; nó không bao giờ ghi ngược. Cấp thêm quyền ghi chỉ mở rộng thiệt hại nếu máy bị chiếm.

Nhiều NAS: khai hồ sơ trên web

Chỉ dùng được khi service đã chạy bằng tài khoản người dùng

Đây không phải cách thay thế cho phần trên — nó là phần thêm vào sau đó. Service còn chạy dưới LocalSystem thì hồ sơ khai ở đây không có tác dụng, và agent sẽ ghi rõ lý do đó vào nhật ký thay vì thử lại mỗi vòng.

Cách khớp tên/mật khẩu ở trên chỉ gọn khi có một NAS. Nhiều NAS với tài khoản khác nhau thì không tạo nổi một tài khoản Windows khớp với tất cả. Lúc đó: chạy service bằng một tài khoản dịch vụ dùng chung, rồi khai từng NAS ở Cấu hình → Truy cập ổ mạng.

Chỉ máy đã duyệt nhận đượcMáy chờ duyệt không nhận mật khẩu nào
Chỉ nhận NAS mình cầnMáy chỉ đọc NAS kế toán không nhận mật khẩu NAS nhân sự
Mật khẩu không chạm đĩaLưu ở mức chỉ-trong-phiên; khởi động lại là mất và agent xin lại từ server
Chỉ agent WindowsMáy Linux mount qua fstab/autofs như cũ

Đánh đổi, nói thẳng

Hôm nay agent không cầm khoá kho lưu trữ — nó chỉ nhận URL ký sẵn cho từng tệp. Chức năng này phá vỡ tính chất đó cho riêng SMB: server giữ mật khẩu NAS và phát xuống các máy cần. Một server bị chiếm là lộ mật khẩu NAS của cả đợt máy. Giảm nhẹ bằng user chỉ đọc trên NAS — agent không bao giờ ghi ngược vào nguồn.

Agent kiểm thật sau khi cấp: nó mở một đường dẫn nguồn trên NAS đó chứ không chỉ tin vào việc ghi credential thành công. Không mở được thì nó hạ xuống mức lưu ra đĩa rồi thử lại, và ghi cảnh báo — vì lúc đó mật khẩu nằm lại trên máy được sao lưu, một đánh đổi không được phép âm thầm.

Bật require_mount cho mọi nguồn mạng

Nhắc lại vì đây là chỗ nó có giá trị nhất: NAS mất kết nối trông y hệt một thư mục rỗng. Không bật cờ này thì mỗi đêm hệ thống báo “sao lưu thành công” trong khi không có tệp nào được lưu.

Kiểm bằng đúng danh tính của service

Xem service đang chạy bằng tài khoản nào — thứ quyết định mọi chuyện ở trên:

sc.exe qc backup-agent | findstr SERVICE_START_NAME

Chạy agentctl trong PowerShell của bạn sẽ cho kết quả SAI

Lúc đó nó chạy bằng tài khoản của bạn, tức là đúng cái danh tính vốn đã có quyền — nên nó báo thành công trong khi service vẫn hỏng. Muốn thử đúng danh tính của service thì phải mở một shell chạy bằng danh tính đó, ví dụ với PsExec -s cho LocalSystem:
PsExec.exe -s -i cmd.exe
dir \\172.16.1.131\Share-SMB
Dòng dir đó chạy được thì agent cũng chạy được, và ngược lại.

Agent nói thẳng nguyên nhân, không chỉ chép lại lỗi Windows

Hai thông báo tối nghĩa của Windows — “user name or password is incorrect” trên đường dẫn UNC và “cannot find the path” trên ổ ánh xạ — đều được agent nhận diện và thay bằng nguyên nhân thật kèm cách sửa, thay vì chép lại nguyên văn lỗi của Windows.

Lịch chạy

Cron 5 trường (phút giờ ngày tháng thứ). Khi khai cả ngày trong tháng lẫn thứ trong tuần, hai điều kiện là HOẶC — giống cron của Unix.

trườngbắt buộcvì sao
cronGiờ chạy
jitter_sec200 máy cùng 0 2 * * * sẽ đồng loạt đập vào kho lưu trữ lúc 2:00:00
windowkhôngvd 22:00-06:00 — ngoài khung giờ này thì bỏ qua lượt

Lỡ giờ thì BỎ QUA, không chạy bù

Máy tắt qua đêm, sáng bật lên sẽ không lập tức chạy một lượt sao lưu đầy đủ. Chạy bù nghĩa là quét toàn bộ đúng lúc người ta bắt đầu làm việc.

Sao lưu tăng dần

Server giữ chỉ mục những tệp đã lưu kèm hash nội dung. Mỗi lượt, agent chỉ đẩy tệp mới hoặc đã đổi.

lượt 1:  4 tệp  →  đẩy 4, bỏ qua 0
lượt 2:  4 tệp  →  đẩy 1, bỏ qua 3   (sửa 1 tệp)
lượt 3:  4 tệp  →  đẩy 0, bỏ qua 4   (không đổi gì)

Tệp lớn

S3 chặn 5 GiB cho một lần ghi. Tệp lớn hơn được chia thành các mảnh 64 MiB và ghép lại ở đích — bản dump database vài chục GB đẩy được bình thường.

Kích thước mảnh64 MiB
Ngưỡng chia mảnh5 GiB, đổi được trong hồ sơ kho lưu trữ
Trần số mảnh10.000 — tức tệp tối đa khoảng 640 GB
Đứt mạng giữa chừngMất lại đúng mảnh đang dở (~3 phút trên đường 3 Mbps), không mất cả tệp

Bỏ dở thì phải huỷ, không được để đó

Mảnh đã đẩy nằm lại trong kho lưu trữ, không hiện ra khi liệt kê, nhưng vẫn bị tính tiền. Agent huỷ ngay khi hỏng; ngoài ra server quét mỗi giờ và huỷ những phiên im lặng quá 12 tiếng. Thiếu bước này thì sau vài tháng là một hoá đơn không ai giải thích nổi.

Cảnh báo & thông báo

Sáu loại cảnh báo

loạinghĩa
no_heartbeatMáy im lặng quá 15 phút
run_failedLượt sao lưu thất bại
run_partialChạy xong nhưng có nguồn lỗi hoặc tệp bị bỏ
upgrade_rollbackNâng cấp thất bại và đã quay về bản cũ
token_reissuedMáy được cấp lại token
reissue_while_aliveCấp lại token trong khi máy cũ vẫn đang sống

Ai gửi: agent hay server

Agent tự gửi
mặc định

Báo được cả khi không gọi tới server — đúng lúc hay xảy ra sự cố nhất. Đổi lại, mỗi máy giữ một bản bot token.

Server gửi

Token không rời khỏi server. Đổi lại, mất server thì mất luôn cảnh báo.

Chống dội tin

Hai lớp, chạy trên chính agent:

cơ chếmặc địnhtác dụng
Trần mỗi giờ6 tin/giờ/kênhMột máy hỏng liên tục không làm ngập nhóm chat
Nghỉ giữa hai tin cùng loại3600 giâyCùng một sự cố không lặp lại mỗi vòng

Tin bị nén lại được đếm và báo kèm trong tin tiếp theo được phép gửi. Nén im lặng sẽ biến “một máy hỏng” và “hai mươi máy hỏng” thành cùng một dòng thông báo.

Định tuyến

Mỗi kênh chọn Nhận tất cả hoặc Chỉ những loại chọn bên dưới. Tab Cảnh báo → Định tuyến hiện loại nào đi tới kênh nào — và tô đỏ loại nào không kênh nào nhận.

Tách kênh vì “máy im lặng” và “sao lưu lỗi” thường là việc của hai người khác nhau. Gộp chung thì một nhóm sẽ mute kênh, và sau đó cả hai loại cùng chìm.

Tin đã gửi

Agent gửi thẳng, rồi báo bản sao về server ở mức ưu tiên thấp — chỉ khi không có lượt sao lưu nào đang chạy, theo lô nhỏ, cách nhau vài phút. Danh sách vì thế có thể trễ vài phút so với tin thật, nhưng nó không tranh băng thông với dữ liệu.

Dòng đáng đọc nhất là dòng gửi hỏng

Tab Cảnh báo → Đã gửi có công tắc Chỉ tin không gửi được. Đó là chỗ phân biệt “không có sự cố” với “có sự cố nhưng người cần biết không nhận được tin”.

Vòng đời một máy

trạng tháinghĩa
chờ duyệtĐã khai báo, chưa được duyệt. Không nhận config thật hay secret nào
đang chạyĐã duyệt. Nhận config và thực thi lịch
đã cho nghỉBiến khỏi fleet, token hết hiệu lực, nhưng lịch sử vẫn còn

Trực tuyến = có gọi về trong 5 phút gần nhất. Im lặng quá 15 phút thì sinh cảnh báo no_heartbeat.

Cho nghỉ hay xoá hẳn

Cho nghỉXoá hẳn
Biến khỏi danh sách
Token hết hiệu lực
Nhật ký, cảnh báo, lịch sử tingiữmất
Chỉ mục tệp đã sao lưugiữmất
Đảo lại đượckhông

Máy cũ đã thay thế: chọn Cho nghỉ

Dọn được danh sách mà vẫn trả lời được “máy kế toán cũ từng sao lưu những gì”. Xoá hẳn mất chỉ mục, nên máy cùng tên cài lại sẽ đẩy lại từ đầu.

Cả hai đều không đụng tới dữ liệu đã nằm trên kho lưu trữ, và cả hai đều không tự gỡ agent trên máy thật — máy đó chỉ mất quyền và sẽ bị từ chối mỗi lần gọi về.

Máy vẫn đang gọi về thì thao tác xoá bị chặn, kèm lý do. Xoá một máy còn sống nghĩa là hệ thống quên nó, còn nó thì vẫn chạy tiếp mà không ai thấy.

Mô hình bảo mật

Nguyên tắcCụ thể
Agent không cầm khoá kho lưu trữChỉ nhận URL ký sẵn cho đúng một tệp, sống 30 phút. Máy bị chiếm không xoá được backup của chính nó
Secret mã hoá trước khi ghiAES-256-GCM, gắn với id bản ghi. Không API nào đọc ngược ra — chỉ còn vân tay 4 byte
Không có phương án ghi plaintextThiếu STORAGE_KEY thì server TỪ CHỐI lưu, chứ không âm thầm ghi thô
Bot token không nằm trong configConfig được hash và trả về cho mọi quản trị viên. Token đi đường riêng
Máy chờ duyệt không nhận gìKhông config thật, không khoá kho lưu trữ, không bot token
Nhật ký thao tác không xoá đượcBảng audit chặn sửa và xoá ở tầng database, và chỉ ghi vân tay chứ không ghi secret
Agent không mở cổngLuôn là bên gọi đi. Không cần mở firewall vào máy được sao lưu

Nhật ký

Agent gửi bản trích nhật ký về server để trả lời “đêm qua máy này có chuyện gì” mà không phải SSH vào chính cái máy đang hỏng.

Giữ7 ngày
Hạn mức500 dòng/giờ/máy — vượt thì bị bỏ và ĐẾM, không im lặng
Nhật ký đầy đủVẫn nằm trên chính máy đó (journalctl -u backup-agent trên Linux)

Số dòng bị bỏ hiện ngay trên đầu danh sách. Im lặng cắt bớt sẽ khiến người đọc tin nhầm rằng khoảng đó không có gì xảy ra.

Khắc phục sự cố

Triệu chứngNguyên nhân thường gặp
Máy hiện “Mất kết nối” nhưng vẫn bậtAgent không gọi ra được (proxy, firewall), hoặc dịch vụ đã dừng. Xem Nhật ký ở trang chi tiết máy
Máy hiện “Lệch config”Đã nhận config mới nhưng chưa áp xong. Gửi lệnh Nạp lại config
Sao lưu báo thành công nhưng 0 tệpỔ mạng chưa mount. Bật require_mount cho nguồn đó để nó thành LỖI thay vì thành công rỗng
Kênh thông báo báo lỗi đỏBấm Gửi thử — Telegram nói rõ lý do (chat not found, bot bị chặn) và hệ thống hiện nguyên văn
Không nhận được cảnh báo nàoXem tab Định tuyến. Loại nào tô đỏ là loại không kênh nào nhận
Trang Cấu hình báo chưa có khoá mã hoáServer thiếu STORAGE_KEY. Đặt biến môi trường rồi khởi động lại server
Sao lưu hoàn tất một phầnCó nguồn lỗi hoặc tệp bị bỏ. Trang chi tiết máy liệt kê đúng nguồn nào
Windows: “The user name or password is incorrect” trên \\nas\shareĐường dẫn đúng, sai là tài khoản của service. Cấp quyền đọc cho tài khoản máy CONGTY\TENMAY$ trên NAS — xem mục Nguồn trên ổ mạng
Windows: “The system cannot find the path” trên X:\…Ổ ánh xạ không tồn tại với service. Khai lại bằng đường dẫn UNC
Tệp lớn hỏng với lỗi 413Kho lưu trữ nằm sau Cloudflare (chặn 100 MB). Đặt ngưỡng multipart về 90 trong hồ sơ kho lưu trữ
Máy đã xoá nhưng vẫn hiện trực tuyếnAgent trên máy đó vẫn chạy. Gỡ bằng uninstall.sh — nó tự báo server trước khi gỡ

Giới hạn đã biết

Những việc hệ thống chưa làm được. Liệt kê ở đây để không ai phát hiện ra chúng vào lúc cần nhất:

  • Chưa có snapshot VSS. Tệp đang bị ứng dụng mở khoá ghi (database đang chạy) có thể không đọc được. Sao lưu ứng dụng sống cần dừng dịch vụ hoặc dump ra trước.
  • Chưa có phục hồi từ giao diện. Dữ liệu nằm trên kho lưu trữ theo đường dẫn đọc được, nhưng phải lấy về thủ công.
  • Nâng cấp agent từ xa chưa bật. Còn thiếu bước ký và kiểm chữ ký bản cài — phát một bản cài không kiểm chữ ký là biến control plane thành công cụ phát tán mã.
  • Chưa có nâng cấp theo đợt. Chưa thử trên một nhóm nhỏ trước khi phát toàn bộ.
  • Windows: chưa hỗ trợ gMSA. Tài khoản dịch vụ riêng vẫn phải khai mật khẩu lúc cài. Muốn hoàn toàn không mật khẩu thì dùng tài khoản máy (cách 1).
  • Windows: tài khoản dịch vụ không đọc được tệp cục bộ bị chặn ACL. Chưa dùng SeBackupPrivilege, nên tài khoản không phải admin chỉ đọc được những gì ACL cho phép. Nguồn trên SMB không vướng chuyện này.