127.0.0.1 SỔ TAY VẬN HÀNH MÁY CHỦ & CỨU HỘ WORDPRESS THỰC CHIẾN
MINH BẠCH

Diễn tập Restore WordPress trên môi trường Staging thứ hai: Từ Checksum đến nghiệm thu giao diện

Hướng dẫn diễn tập Restore WordPress vào thư mục và Database MariaDB độc lập trên VPS lab; kiểm tra Checksum, cấu trúc archive, đổi URL và nghiệm thu đăng nhập.

Bảo mật & Sao lưu // localhost.vn
Mục lục bài viết (13 mục)
ĐÚC KẾT THỰC CHIẾN

Giải nén tar không báo lỗi hay khớp Checksum mới chỉ là điều kiện cần; chỉ khi bạn tự tay dựng lại bản Restore độc lập, đổi URL và đăng nhập thành công mà không làm ảnh hưởng site gốc thì phao cứu sinh mới thực sự dùng được.

Phạm vi đã thử: Bên cạnh đợt diễn tập ngày 30/09, vào ngày 01/10/2026 chúng tôi đã tiến hành khôi phục (Restore) chính bộ Backup lưu trữ vào một cây thư mục và cơ sở dữ liệu MariaDB tách biệt hoàn toàn trên cùng máy chủ VPS: xác minh qua HTTP client lúc 12:21, sau đó mở trình duyệt nghiệm thu giao diện khách, luồng đăng nhập và đăng xuất vào lúc 21:41. Môi trường đích chỉ lắng nghe trên giao diện loopback nội bộ. Nhánh thực nghiệm lúc 12:36 kéo dữ liệu qua máy Mac được bóc tách riêng; lưu ý rằng các đợt chạy này chưa nghiệm thu thư viện ảnh (Media Library), biểu mẫu/email hay đo tổng thời gian cứu hộ toàn diện (RTO).

Cách duy nhất để thoát khỏi cái bẫy “Backup của Schrödinger” — tức là bản sao lưu nhìn thì có vẻ tồn tại nhưng lúc hữu sự mở ra lại hỏng — chính là lôi nó ra dựng lại trên một môi trường Staging thứ hai, rồi tận mắt kiểm tra bài viết, hình ảnh, khung đăng nhập cũng như cơ chế khóa mõm các luồng gửi email/webhook thật. Trong bài thực hành này, chúng ta sẽ thiết lập một trang đích độc lập ngay trên cùng chiếc VPS lab để diễn tập toàn bộ quy trình mà không tốn tiền thuê thêm máy chủ thứ hai.

Tất nhiên, cần nói thẳng với nhau ngay từ đầu: việc tách thư mục và Database trên cùng một chiếc VPS chỉ giúp bạn rèn luyện thao tác kỹ thuật chuẩn xác và tránh ghi đè nhầm lên trang gốc, chứ hoàn toàn không cứu được bạn nếu cả chiếc máy chủ vật lý đó bốc khói. Bạn vẫn bắt buộc phải duy trì bản sao lưu ngoài máy (offsite backup). Mục tiêu tối thượng của bài tập hôm nay là kiểm định quy trình thao tác và độ đầy đủ của gói Backup bằng bộ dữ liệu mẫu an toàn.

Điều kiện để thực hành đúng phạm vi

Bài viết dành cho những anh em đã đi qua lộ trình WordPress trên VPS từ A đến Z và đang nắm quyền điều khiển một máy chủ lab riêng biệt. Cấu hình mẫu của chúng ta vẫn là bộ tứ quen thuộc: Ubuntu 24.04 LTS, Nginx, PHP 8.3 và MariaDB 10.11. Hãy dành ít phút rà soát lại phiên bản phần mềm, tên service và cấu trúc đường dẫn trên máy của bạn trước khi chạy lệnh, bởi kết quả thực tế luôn phụ thuộc vào cấu hình hạ tầng cụ thể.

Nguyên tắc kỷ luật thép khi diễn tập Restore: phải tách biệt hoàn toàn cây thư mục mã nguồn, cơ sở dữ liệu và tài khoản người dùng Database của bản đích khỏi bản nguồn, đồng thời chỉ sử dụng dữ liệu thử nghiệm có gắn nhãn rõ ràng. Vì gói Backup mang theo toàn bộ danh sách tài khoản WordPress từ trang gốc, bạn chỉ được phép đăng nhập bằng tài khoản lab đã cấp phép, tuyệt đối không tự ý tạo thêm quyền Administrator hay phơi bày bản clone này ra ngoài Internet công cộng. Hãy gán các biến môi trường viết hoa theo đúng đường dẫn đã xác minh trên lab, giữ kín mật khẩu bên ngoài bài viết, lịch sử shell và kho chứa Git. Nếu thiếu công cụ nào thì cứ bình tĩnh đọc tài liệu chính thức để cài đặt — dòng báo lỗi “command not found” của shell không có nghĩa là website của bạn bị hỏng. Các sơ đồ dưới đây dùng để minh họa luồng tư duy thao tác, không thay thế cho ảnh chụp kết quả thực nghiệm.

Tách nguồn và đích: Thư mục mới; Database trống riêng; User DB chỉ quyền đích; Vhost lab bị hạn chế

Minh họa kiến trúc 1: cô lập hoàn toàn giữa nguồn và đích. Sơ đồ do đội ngũ localhost.vn biên soạn; không phải ảnh chụp màn hình hay số liệu từ máy lab.

Chuẩn bị một đích chưa chứa dữ liệu

Bước đầu tiên là chọn một đường dẫn RESTORE_ROOT mới tinh, nằm tách biệt hoàn toàn bên ngoài cây thư mục webroot của trang nguồn. Áp dụng đúng quy chuẩn tạo cơ sở dữ liệu đã học, bạn hãy khởi tạo một Database trống hoàn toàn mới kèm theo một tài khoản người dùng (DB user) chỉ được cấp quyền gói gọn bên trong đúng Database phục hồi đó. Hãy ghi thật rõ tên nguồn và tên đích ra giấy nhớ hoặc màn hình phụ rồi đối chiếu từng chữ trước khi gõ lệnh import. Tai nạn kinh điển nhất của dân kỹ thuật khi diễn tập Restore chính là giải nén mã nguồn ra thư mục mới nhưng quên sửa file cấu hình, để rồi bản Staging hồn nhiên kết nối thẳng vào Database của trang Production đang chạy thật!

Ở tầng web server, hãy cấu hình một vhost chỉ lắng nghe trên địa chỉ nội bộ loopback (127.0.0.1) hoặc một tên miền phụ (subdomain) thử nghiệm đã khóa chặt quyền truy cập bằng mật khẩu hay giới hạn IP. Trước khi cho phép PHP xử lý bất kỳ request nào, hãy đảm bảo bạn đã chặn đứng đường gửi email ra ngoài, vô hiệu hóa các cổng thanh toán tự động và ngắt toàn bộ webhook trên bản clone. Đừng bao giờ mở toang một bản clone chứa nguyên danh sách tài khoản khách hàng cũ ra ngoài Internet; một thẻ noindex trong file robots.txt chỉ là lời khuyên lịch sự với công cụ tìm kiếm chứ hoàn toàn không phải hàng rào bảo mật ngăn chặn truy cập trái phép.

Kiểm bộ sao lưu rồi giải nén riêng

Bộ sao lưu tiêu chuẩn nằm trong thư mục BACKUP_DIR sẽ bao gồm gói nén wordpress.tar.gz, bản xuất database.sql và tệp chứa mã băm Checksum đáng tin cậy. Hãy truyền đường dẫn tuyệt đối đã xác minh vào các biến thư mục thay vì để nguyên giá trị giữ chỗ (placeholder). Biến CHECKSUM_FILE phải trỏ tới đúng tệp mã băm được sinh ra lúc tạo Backup; tuyệt đối không chơi trò tự băm lại một tệp đang nghi ngờ bị lỗi chỉ để ép kết quả báo khớp. Đường dẫn đích RESTORE_ROOT bắt buộc phải chưa từng tồn tại trên đĩa (kể cả dưới dạng một symlink đứt gãy), và thư mục cha của nó phải nằm dưới quyền kiểm soát độc quyền của bạn để không ai có thể tráo đổi đường dẫn giữa chừng. Nếu bộ Backup gốc đang thuộc quyền sở hữu độc quyền của root, hãy nhờ quản trị viên hệ thống nhân bản một bản sao riêng cấp quyền đọc cho tài khoản thực hành của bạn rồi đối chiếu lại mã băm, chứ đừng bao giờ nới lỏng quyền của kho Backup gốc hay nhắm mắt dùng lệnh sudo tar giải nén bằng quyền root để lách qua lỗi phân quyền.

(
  set -eu
  : "${BACKUP_DIR:?Chọn bộ backup lab ngoài webroot}"
  : "${CHECKSUM_FILE:?Đặt tên file checksum của bộ backup}"
  case "$BACKUP_DIR" in /*) ;; *) exit 1 ;; esac
  test "$(id -u)" -ne 0
  test -d "$BACKUP_DIR"
  BACKUP_DIR=$(realpath -e -- "$BACKUP_DIR")
  test -r "$BACKUP_DIR/$CHECKSUM_FILE"
  test -r "$BACKUP_DIR/wordpress.tar.gz"
  test -s "$BACKUP_DIR/database.sql"
  (cd "$BACKUP_DIR" && sha256sum -c -- "$CHECKSUM_FILE")
  gzip -t "$BACKUP_DIR/wordpress.tar.gz"
  umask 077
  AUDIT_DIR=$(mktemp -d -- "$HOME/restore-inspect.XXXXXX")
  tar -tvzf "$BACKUP_DIR/wordpress.tar.gz" \
    --quoting-style=escape > "$AUDIT_DIR/archive-members.txt"
  printf 'Danh sách đầy đủ: %s/archive-members.txt\n' "$AUDIT_DIR"
  less "$AUDIT_DIR/archive-members.txt"
)

Cơ chế an toàn của khối lệnh trên là hễ Checksum sai lệch, luồng nén gzip bị hỏng hoặc lệnh đọc danh sách gặp trục trặc thì toàn bộ quá trình sẽ phanh gấp ngay lập tức. Danh sách chi tiết (verbose list) được xuất ra tệp sẽ ghi nhận đầy đủ mọi thành phần và kiểu tệp tin bên trong gói nén chứ không chỉ cắt cụt 20 dòng đầu tiên. Hãy dành thời gian rà soát toàn bộ nội dung gói archive do bạn tạo ra: một gói sao lưu WordPress lành mạnh trong bài tập này chỉ nên chứa tệp tin thông thường (regular files) và thư mục (directories). Nếu bạn phát hiện thấy liên kết mềm (symlink), liên kết cứng (hard link), tệp thiết bị (device node), đường dẫn tuyệt đối bắt đầu bằng dấu /, chuỗi nhảy thư mục cha .. hay những đường dẫn trùng lặp kỳ dị, hãy dừng tay ngay lập tức để điều tra nguyên nhân trước khi giải nén. Hãy cất giữ tệp danh sách này ở nơi an toàn, và sau khi hoàn tất chỉ xóa đúng các tệp trung gian vừa sinh ra trong bước kiểm định.

Trong trường hợp tệp Checksum hiện có mới chỉ chứa mã băm của gói .tar.gz, bạn hãy đối chiếu thêm chuỗi SHA-256 của bản xuất .sql dựa trên hồ sơ manifest gốc, bởi cả hai mảnh ghép này đều cần được xác thực độc lập. Bộ sao lưu tạo lúc 02:16 ngày 01/10 của chúng ta đã có sẵn cả wordpress.sha256 lẫn tệp manifest đầy đủ. Lưu ý rằng gói archive đóng gói theo quy chuẩn của bài 53 lấy ngay nội dung bên trong thư mục website làm gốc. Khi mọi bước thẩm định trên đều đã lên đèn xanh, hãy tiến hành giải nén bằng chính tài khoản người dùng thực hành thông thường:

(
  set -eu
  : "${BACKUP_DIR:?Chọn đúng bộ đã kiểm}"
  : "${SOURCE_ROOT:?Đặt webroot nguồn để tránh nhầm}"
  : "${RESTORE_ROOT:?Chọn thư mục phục hồi mới}"
  case "$BACKUP_DIR" in /*) ;; *) exit 1 ;; esac
  case "$SOURCE_ROOT" in /*) ;; *) exit 1 ;; esac
  case "$RESTORE_ROOT" in /*) ;; *) exit 1 ;; esac
  test "$(id -u)" -ne 0
  test -r "$BACKUP_DIR/wordpress.tar.gz"
  test ! -e "$RESTORE_ROOT"
  test ! -L "$RESTORE_ROOT"
  SOURCE_ROOT=$(realpath -e -- "$SOURCE_ROOT")
  RESTORE_ROOT=$(realpath -m -- "$RESTORE_ROOT")
  case "$RESTORE_ROOT/" in
    "$SOURCE_ROOT/"*) printf 'Đích nằm trong nguồn; dừng\n' >&2; exit 1 ;;
  esac
  umask 077
  mkdir -m 700 -- "$RESTORE_ROOT"
  tar -xzf "$BACKUP_DIR/wordpress.tar.gz" -C "$RESTORE_ROOT" \
    --no-same-owner --no-same-permissions
  test -f "$RESTORE_ROOT/wp-load.php"
  test -f "$RESTORE_ROOT/wp-config.php"
  printf 'Đã giải nén; chưa mở vhost hoặc chạy WordPress.\n'
)

Khối lệnh được thiết kế để tự động dừng ngay nếu lệnh mkdir phát hiện thư mục đích đã tồn tại hoặc bất kỳ bước nào trả về mã lỗi. Nếu cần làm lại, hãy chọn một tên thư mục đích mới tinh thay vì dùng lệnh rm -rf xóa đè lên thư mục cũ. Trong trường hợp tiến trình tar bị đứt gánh giữa đường, hãy giữ nguyên hiện trường thư mục đang giải nén dở để khám nghiệm lỗi và tuyệt đối không trỏ web server vào đó. Thiết lập umask 077 kết hợp cùng hai cờ không khôi phục quyền sở hữu/phân quyền cũ giúp khóa chặt thư mục đích ở trạng thái riêng tư ngay khi vừa bung ra. Tất nhiên, trước khi đưa vào vận hành dưới tiến trình PHP-FPM, bạn sẽ cần rà soát và cấp lại quyền đọc cũng như quyền duyệt thư mục (traverse) chuẩn xác cho tài khoản dịch vụ web, bởi phân quyền mặc định ngay sau khi giải nén thường rất khắt khe.

Lưu ý kỹ thuật phân biệt hai bộ dữ liệu trên lab: Bộ sao lưu tạo ngày 30/09 mang tên site-files.tar.gz có chứa một thư mục vỏ bọc bên ngoài, do đó đợt khôi phục hôm ấy phải truyền thêm tham số --strip-components=1 khi giải nén vào thư mục đích. Ngược lại, gói wordpress.tar.gz lưu trữ từ lúc 02:16 ngày 01/10 chứa 4.012 tệp tin được đóng gói trực tiếp từ gốc nội dung website mà không có lớp vỏ thư mục bọc ngoài (bản SQL đi kèm có 12 bảng, 0 bản ghi attachment, và hai tệp gắn nhãn thử nghiệm bên trong không phải là ảnh media thực tế của WordPress). Kinh nghiệm xương máu là chỉ sử dụng cờ --strip-components=1 sau khi bạn đã đọc kỹ danh sách tệp trong archive và thấy rõ lớp vỏ thư mục thừa; nếu áp dụng máy móc tham số này cho gói nén không có lớp vỏ bọc như mẫu trên, bạn sẽ vô tình cắt cụt mất tầng đầu tiên của các thư mục con như wp-admin, wp-includes và wp-content.

Console LAB-CF-02 kiểm bộ backup giữ lại: giải nén 4012 file khớp archive, chưa nhập SQL hoặc chạy website trong lượt 11:33

Ảnh chụp màn hình console thực tế lúc 11:33:45 ngày 01/10/2026 (UTC+7), giữ nguyên độ phân giải gốc kèm logo nhận diện. Kịch bản hỗ trợ chạy trực tiếp trong khung 11:33:10–16 để thẩm định gói archive tạo lúc 02:16 và đối chiếu khớp toàn bộ 4.012 đường dẫn cùng mã băm SHA-256 sau khi giải nén. Dấu thời gian hiển thị trong ảnh tính theo múi giờ UTC. Lưu ý đây là bằng chứng nghiệm thu bước giải nén gói archive, chưa phải bước nạp SQL, đăng nhập quản trị hay vận hành ứng dụng. Nhấp vào ảnh để xem rõ chi tiết.

Luồng khôi phục: Kiểm checksum; Giải nén đúng gốc; Nhập SQL vào đích; Đổi URL bằng dry-run

Minh họa kiến trúc 2: trình tự khôi phục chuẩn chỉnh. Sơ đồ do localhost.vn thiết kế; không phải ảnh chụp màn hình hay số liệu từ máy lab.

Nhập database và đổi cấu hình ở bản phục hồi

Tiếp theo, hãy nạp tệp SQL vào cơ sở dữ liệu trống vừa tạo theo đúng quy trình an toàn ở bài 52, sau đó mở tệp wp-config.php nằm trong thư mục vừa giải nén bằng trình soạn thảo văn bản trên terminal để cập nhật thông tin kết nối. Hãy kiểm tra từng ký tự của các hằng số DB_NAME, DB_USER, DB_HOST và biến $table_prefix; tuyệt đối không truyền mật khẩu trực tiếp trên dòng lệnh hay để lộ trong tài liệu báo cáo. Nếu bộ dữ liệu gốc có chứa thông tin thật, đừng quên làm mới toàn bộ bộ khóa muối xác thực (Authentication Unique Keys and Salts) và rà soát lại danh sách quyền hạn trước khi cấp phép cho bất kỳ ai truy cập vào môi trường clone.

Tuyệt đối chỉ thực hiện lệnh đổi tên miền (search-replace URL) sau khi bạn đã xác minh chắc chắn 100% rằng công cụ WP-CLI đang đọc đúng cây thư mục đích và kết nối vào đúng Database phục hồi. Hãy luôn khởi động bằng chế độ chạy thử (--dry-run) và giữ nguyên vẹn giá trị cột guid của các bài viết.

(
  set -eu
  : "${SOURCE_ROOT:?Đặt webroot nguồn để đối chiếu}"
  : "${RESTORE_ROOT:?Đặt webroot phục hồi đã kiểm}"
  : "${RESTORE_DB:?Đặt tên DB riêng của đích}"
  : "${RESTORE_DB_USER:?Đặt user chỉ có quyền DB đích}"
  : "${OLD_URL:?URL nguồn lab đã kiểm}"
  : "${NEW_URL:?URL đích lab đã kiểm}"
  case "$SOURCE_ROOT" in /*) ;; *) exit 1 ;; esac
  case "$RESTORE_ROOT" in /*) ;; *) exit 1 ;; esac
  test "$(id -u)" -ne 0
  test -O "$RESTORE_ROOT"
  test "$OLD_URL" != "$NEW_URL"
  test ! -L "$RESTORE_ROOT"
  SOURCE_ROOT=$(realpath -e -- "$SOURCE_ROOT")
  RESTORE_ROOT=$(realpath -e -- "$RESTORE_ROOT")
  case "$RESTORE_ROOT/" in
    "$SOURCE_ROOT/"*) printf 'Nhầm phạm vi nguồn; dừng\n' >&2; exit 1 ;;
  esac
  test -f "$RESTORE_ROOT/wp-config.php"
  test "$(wp --path="$RESTORE_ROOT" config get DB_NAME)" = "$RESTORE_DB"
  test "$(wp --path="$RESTORE_ROOT" config get DB_USER)" = "$RESTORE_DB_USER"
  wp --path="$RESTORE_ROOT" search-replace "$OLD_URL" "$NEW_URL" \
    --all-tables-with-prefix --skip-columns=guid --dry-run
)

Trước khi gõ Enter, hãy rà soát thêm một lần nữa xem giá trị DB_HOST, phạm vi quyền của tài khoản Database và các hằng số đường dẫn cứng như ABSPATH hay WP_HOME/WP_SITEURL (nếu có khai báo trong file cấu hình) đã trỏ đúng về bản phục hồi chưa. Hãy nhớ rằng tham số --path của WP-CLI chỉ chỉ định thư mục chứa mã nguồn cần nạp, chứ nó không tự động sửa giúp bạn tệp wp-config.php nếu tệp đó vẫn đang trỏ nhầm về Database nguồn! Hãy đọc kỹ bảng thống kê số lượng ô dữ liệu dự kiến sẽ thay đổi sau khi chạy --dry-run; chỉ khi thấy con số hoàn toàn hợp lý thì mới chạy lại khối lệnh kiểm tra đầu vào và bỏ cờ --dry-run ở câu lệnh cuối cùng. Đừng bao giờ dùng lệnh sed hay tìm-thay văn bản thô trực tiếp trên file .sql, bởi cách làm thô bạo đó sẽ phá vỡ độ dài chuỗi trong cấu trúc dữ liệu tuần tự hóa (PHP serialized data) của WordPress và các plugin. Quy trình này áp dụng cho mô hình trang đơn (single-site); với hệ thống WordPress Multisite hoặc các plugin đóng gói URL theo định dạng riêng, bạn sẽ cần kịch bản chuyển đổi chuyên biệt.

Mở bản phục hồi trong phạm vi lab

Bây giờ, hãy tạo một tệp cấu hình vhost mới dựa trên mẫu chuẩn sẵn có, trỏ đường dẫn root về thư mục RESTORE_ROOT và gán tên miền nội bộ dành riêng cho bản đích. Gõ cụm lệnh quen thuộc sudo nginx -t && sudo systemctl reload nginx để đảm bảo Nginx chỉ nạp lại cấu hình khi cú pháp không có lấy một lỗi nhỏ. Hãy kiểm tra xem tiến trình PHP-FPM đã đọc được mã nguồn và có quyền ghi vào đúng thư mục uploads của bản đích chưa — và xin nhắc lại, tuyệt đối không bao giờ dùng “bùa bẩn” chmod -R 777 chỉ để dập tắt lỗi phân quyền. Nếu vhost chỉ lắng nghe trên giao diện loopback, bạn có thể tạo một đường hầm chuyển tiếp cổng qua SSH (SSH port forwarding/tunnel) ngay trong phiên làm việc được cấp phép để mở trên trình duyệt máy cá nhân.

Khi trang web đã lên hình, hãy đi một vòng kiểm tra từ trang chủ, một bài viết cũ, bài viết mới nhất, hình ảnh gốc, cấu trúc đường dẫn tĩnh (permalink) cho tới khu vực quản trị /wp-admin/. Nếu thử nghiệm tính năng gửi biểu mẫu (form), hãy đảm bảo thư chỉ đi vào hộp thư nội bộ (như Mailpit/Mailhog) hoặc hố đen thử nghiệm. Hãy bấm đồng hồ đo tổng thời gian khôi phục tính từ giây phút bắt đầu lấy bản Backup cho đến khi tích chọn hoàn tất toàn bộ các bài kiểm tra chức năng này, chứ đừng vội dừng bấm giờ ngay lúc thanh tiến trình giải nén tar vừa chạy xong.

Kiểm kết quả và giới hạn kết luận

Để nghiệm thu nghiêm túc, hãy đặt bản nguồn và bản đích cạnh nhau rồi đối chiếu tổng số bài viết đã xuất bản (published posts), mã ID của bài viết mẫu, hình ảnh hiển thị và các thiết lập cấu hình quan trọng. Một trang web trả về mã trạng thái HTTP 200 OK vẫn có thể đang hiển thị một giao diện trắng trơn hoặc mất sạch dữ liệu bên trong, vì vậy việc kiểm tra nội dung thực tế là bước không thể bỏ qua. Hãy ghi chép lại thời gian tiêu tốn của từng công đoạn để biết điểm nghẽn nằm ở khâu tải file qua mạng, giải mã, nạp SQL hay tinh chỉnh cấu hình. Lưu ý rằng các số đo trong phạm vi bài tập nội bộ này mới chỉ phản ánh thời gian thao tác kỹ thuật cục bộ, chưa bao gồm toàn bộ quy trình ứng cứu thảm họa để kết luận chỉ số RTO cuối cùng.

Nghiệm thu chức năng: Bài cũ và bài mới; Ảnh và permalink; Đăng nhập quản trị; Mail không ra ngoài

Minh họa kiến trúc 3: bốn hạng mục nghiệm thu chức năng sau khi Restore. Sơ đồ do localhost.vn biên soạn; không phải ảnh chụp màn hình hay số liệu từ máy lab.

Kết quả thực trên LAB-CF-02 ngày 30/09/2026

Biên bản thực nghiệm sao lưu, khôi phục và kiểm định tính cô lập cơ sở dữ liệu vào ngày 30/09 ghi nhận kết quả thực tế trên cùng máy chủ VPS lab như sau:

Bước Kết quả quan sát
Bộ sao lưu WP-CLI export ra site.sql; SHA256 của dump và site-files.tar.gz đều khớp
Giải nén và nhập DB Archive có thư mục bao ngoài, giải nén với --strip-components=1; WP-CLI import vào DB của bản phục hồi thành công
Đổi URL search-replace dry-run dự kiến 5 thay thế, lần áp dụng ghi 5; bỏ cột guid
Đích web Vhost http://restore-cf02.test:8081 chỉ lắng nghe 127.0.0.1; nginx -t đạt
Kiểm dữ liệu Site nguồn và restore đều có 2 bài xuất bản; permalink bài thử trả đúng nội dung
Hậu kiểm lúc 23:20 (UTC+7) Hai user DB đã tách; mỗi user đọc được DB riêng, bị từ chối DB bên kia và schema mysql; wp db check đạt 12 bảng mỗi DB
Bảo toàn cấu hình Cấu hình site nguồn không đổi; cấu hình restore hợp lệ và giữ mode 640

Có một chi tiết thực tế rất đáng chia sẻ: ở lần dựng đầu tiên trong ngày 30/09, bản phục hồi từng dùng chung tài khoản người dùng Database với trang nguồn. Đến đợt hậu kiểm lúc 23:20, điểm yếu này đã được khắc phục triệt để bằng cách tách riêng hai tài khoản và đối chiếu lại số lượng bài viết cùng permalink cả trước lẫn sau khi thu hồi quyền cũ. Tất nhiên, phép kiểm chứng này chỉ xác nhận đúng phạm vi của hai tài khoản và đường kết nối vừa thử, chứ chưa phải bài kiểm toán bảo mật (audit) toàn bộ hệ thống phân quyền trên máy chủ.

Trong đợt chạy ngày 30/09, bản clone đã được bật hằng số DISABLE_WP_CRON, nhưng cần nhớ rằng chỉ riêng hằng số này không đủ để bảo chứng việc chặn đứng mọi luồng gửi email hay gọi webhook ra ngoài. Đợt thực nghiệm hôm ấy cũng chưa kiểm tra thao tác đăng nhập Dashboard qua trình duyệt, chưa nghiệm thu ảnh/thumbnail, biểu mẫu, email, chỉ số RTO, kho lưu trữ offsite hay khôi phục từ Snapshot. Ngoài ra, do bản Snapshot của VPS được chụp trước thời điểm chúng ta tách riêng quyền tài khoản Database, nếu sau này bạn khôi phục máy chủ từ bản Snapshot đó thì bắt buộc phải thực hiện lại bước tách quyền Database. Các sơ đồ trong bài chỉ mang tính giải thích quy trình, còn bức ảnh console lúc 11:33 phía trên chỉ ghi nhận bước thẩm định gói nén archive.

Phục hồi bộ đã lưu và kiểm chức năng ngày 01/10

Trong khung thời gian 12:21:46–12:22:02 ngày 01/10/2026 (UTC+7), chúng tôi thực hiện khôi phục từ chính bộ archive và SQL đã lưu trữ lúc 02:16 rạng sáng. Môi trường đích là một thư mục mới tinh đi kèm một Database và tài khoản người dùng tạm thời vừa khởi tạo (chỉ cấp đúng một quyền GRANT trên schema đích, không có GRANT OPTION); cả trang nguồn lẫn trang đích đều nằm trên máy LAB-CF-02. Ngay sau khi xác minh mã băm của toàn bộ tệp giải nén, tệp cấu hình ở bản đích được cập nhật sang thông tin Database mới và đường dẫn mới trước khi khởi chạy WordPress.

Bước kiểm Kết quả thực tế
File từ bộ giữ lại 4012 đường file và SHA-256 khớp archive trước khi sửa cấu hình đích; không strip thư mục
Nhập SQL Client MariaDB thật qua PTY nhận prompt, echo tắt, exit 0; không mật khẩu trong đối số tiến trình
WordPress và URL 7.1.2; 2 bài xuất bản, 0 attachment; dry-run 5 và áp dụng 5 thay thế, bỏ guid; blog_public=0, DB check đạt
Máy chủ thử PHP builtin chạy bằng tutorial UID 1000, chỉ nghe 127.0.0.1:8082; không phải vhost nginx/PHP-FPM mới
Nội dung web Trang chủ và permalink HTTP 200, đúng tiêu đề tiếng Việt; header riêng xác nhận request đến đúng đích phục hồi
File tĩnh File văn bản thử trong uploads HTTP 200 và SHA khớp archive; không phải ảnh hoặc thumbnail
Xác thực Khách vào /wp-admin/ được chuyển tới form login; HTTP client POST đăng nhập, nhận cookie xác thực và trang admin 200
Dọn và bảo toàn Server dừng, port đóng, cây file/DB/user tạm bị xóa; hash hai cấu hình và bốn file backup không đổi, hai site hiện hữu giữ nội dung trước/sau

Trên môi trường đích của đợt chạy này, hàm gửi mail mặc định của PHP đã bị vô hiệu hóa, các bộ lọc (filters) chặn gửi mail và gọi kết nối HTTP ra ngoài của WordPress đều được kích hoạt, đồng thời việc gọi trực tiếp vào đường dẫn cron trả về mã lỗi 403 Forbidden — đảm bảo không một bức thư nào lọt ra ngoài. Tất nhiên, các chốt chặn này chỉ bảo vệ những luồng đi qua chuẩn API của WordPress đã kiểm chứng, chứ chưa thể khóa cứng các plugin tự ý mở kết nối socket riêng. Bước kiểm tra đăng nhập lúc 12:21 được thực hiện tự động thông qua HTTP client và cookie, chưa mở giao diện Dashboard trên trình duyệt đồ họa (phần nghiệm thu bằng trình duyệt thực tế được thực hiện riêng vào lúc 21:41 ở mục ngay dưới đây). Bên cạnh đó, do gói Backup gốc có 0 bản ghi attachment, tệp văn bản mẫu trong thư mục uploads chỉ dùng để xác nhận đường dẫn tệp tĩnh chứ không thay thế được việc kiểm tra thư viện ảnh Media Library hay các kích cỡ ảnh thu nhỏ (thumbnails).

Cũng xin kể thật một tình huống vấp ngã lúc 12:19 ngay trước đó: ở lần chạy thử đầu tiên, khi gửi request chưa đăng nhập vào đường dẫn thư mục /wp-admin/, máy chủ PHP tích hợp (built-in server) bị vướng lỗi điều hướng do script router chưa xử lý tự động tệp index.php trong thư mục con; toàn bộ dữ liệu tạm của lần vấp đó đã được xóa bỏ. Ngay sau khi bổ sung logic xử lý đường dẫn thư mục vào router, đợt chạy lúc 12:21 mới vượt qua mượt mà cả bài kiểm tra khách lẫn quản trị viên. Nguyên tắc làm việc rõ ràng: một lần chạy dở dang tuyệt đối không được tính là đã Restore thành công.

Con số tổng thời gian 14,915 giây ghi nhận trong log chỉ tính từ lúc script bắt đầu bung gói Backup có sẵn trên ổ đĩa cho đến khi hoàn tất các bài kiểm tra tự động trên lab. Nó hoàn toàn chưa tính thời gian tải dữ liệu từ kho lưu trữ đám mây về, thời gian khởi tạo VPS mới và quy trình nghiệm thu thủ công, nên đừng nhầm lẫn con số này với chỉ số RTO thực tế. Đợt chạy 12:21 cũng chưa thử nghiệm biểu mẫu liên hệ, giao diện Media Library, luồng gửi mail, khôi phục Snapshot hay dựng web từ gói lưu trữ ngoài máy.

Phân biệt với nhánh lấy bộ từ ngoài VPS

Chỉ mười lăm phút sau, vào lúc 12:36:35–12:37:11 (giờ Việt Nam) ngày 01/10, một nhánh thực nghiệm độc lập khác đã tiến hành khôi phục bốn tệp Backup WordPress từ kho lưu trữ restic đặt trên máy Mac (sau khi đã xóa kho thử nghiệm từ xa), rồi truyền ngược chính bộ tệp vừa cứu về đó lên một thư mục đích hoàn toàn mới trên VPS. Kịch bản này tuyệt đối không ăn gian bằng cách lấy lại tệp đang nằm sẵn trên ổ cứng VPS. Kết quả kiểm định cũng xác nhận khớp toàn bộ 4.012 tệp tin, nạp SQL trơn tru, hệ thống WordPress 7.1.2 hiển thị đúng hai bài viết cùng 0 attachment, trang chủ/permalink phản hồi chuẩn xác và đăng nhập quản trị qua HTTP client thành công.

Như vậy, nhánh 12:36 đóng vai trò xác minh khả năng khôi phục từ nguồn dữ liệu đã đi ra ngoài máy (offsite), trong khi nhánh 12:21 kiểm tra bộ lưu trữ tại chỗ (local retention) — hai luồng dữ liệu này được ghi nhận tách biệt, không nhập nhằng. Dù vậy, đích đến của nhánh 12:36 vẫn nằm trên cùng chiếc VPS cũ và tệp trong uploads vẫn chỉ là văn bản thử nghiệm, nên chúng ta vẫn chưa hoàn thành bài toán dựng lại trên một máy chủ vật lý hoàn toàn khác, chưa nghiệm thu giao diện media/form/email và chưa đo đạc RPO/RTO thực chiến. Toàn bộ kho tạm, tệp trung gian và thư mục đích đã được dọn sạch sau khi chạy xong.

Kiểm giao diện bản phục hồi lúc 21:41

Để mảnh ghép nghiệm thu trọn vẹn cả phần nhìn, vào lúc 21:40:49–21:41:20 ngày 01/10/2026 (UTC+7), chúng tôi thực hiện thêm một đợt dựng lại từ bộ Backup lưu trữ lúc 02:16 vào một cây thư mục và cặp Database/user tạm mới trên máy LAB-CF-02. Trước khi mở trình duyệt, cả 4.012 tệp tin đều được xác nhận khớp mã băm SHA-256, nạp SQL thành công, WordPress 7.1.2 báo có hai bài xuất bản và 0 attachment. Lệnh đổi URL ở cả bước --dry-run lẫn lúc chạy thật đều cập nhật đúng 5 vị trí (bỏ qua cột guid); lệnh wp db check báo đạt và thiết lập blog_public=0 được bật. Máy chủ thử nghiệm chỉ lắng nghe trên địa chỉ loopback và được kết nối qua đường hầm SSH tunnel từ máy cá nhân, đảm bảo không phơi bày bản clone ra ngoài Internet.

1. Kiểm tra bài viết dưới góc nhìn khách truy cập (Guest session). Mở đường dẫn tĩnh (permalink) của bài viết mẫu trên trình duyệt chưa đăng nhập, đối chiếu tiêu đề và đoạn văn bản tiếng Việt với bản gốc. Đợt kiểm tra này xác nhận phản hồi có chứa HTTP header định danh đúng môi trường clone, mã trạng thái HTTP 200, hiển thị tiếng Việt có dấu chuẩn xác và hoàn toàn không xuất hiện thanh công cụ Admin Bar ở cả hai độ rộng màn hình 1440 px lẫn 390 px.

Bài thử kiểm permalink trên WordPress phục hồi ở chiều rộng 1440 px, đúng nội dung tiếng Việt

Ảnh chụp trình duyệt thực tế lúc 21:41:13 ngày 01/10/2026 (UTC+7), hiển thị phần đầu giao diện khách trên bản phục hồi từ bộ lưu trữ nội bộ. Toàn bộ pixel vùng nội dung được giữ nguyên bản, phần chân ảnh gắn thêm logo nhận diện; bấm vào ảnh để xem bản cắt đầy đủ. Lưu ý đây không phải ảnh chụp của nhánh khôi phục offsite lúc 12:36.

2. Kiểm tra hiển thị trên khung hình hẹp (Mobile viewport). Thu hẹp kích thước khung nhìn trình duyệt về mức 390 px, đọc lại nội dung bài viết và kiểm tra xem có bị vỡ khung hay tràn thanh cuộn ngang không. Đây là bước kiểm tra giao diện đáp ứng (responsive) ngay trên trình duyệt máy tính thông qua SSH tunnel, chưa phải thử nghiệm trên thiết bị điện thoại vật lý qua sóng 4G/5G. Bức ảnh dưới đây giữ nguyên chiều ngang 390 px để bạn dễ dàng quan sát cách ngắt dòng của tiêu đề tiếng Việt.

Bài WordPress phục hồi ở viewport 390 px, tiêu đề và nội dung xuống dòng trong màn hình

Ảnh chụp giao diện khách lúc 21:41:14 ngày 01/10/2026 (UTC+7) ở độ rộng 390 px trên cùng bản phục hồi. Giữ nguyên pixel gốc kèm chân trang có logo; bấm vào ảnh để xem chi tiết.

3. Nghiệm thu luồng đăng nhập, danh sách bài viết và đăng xuất. Khi một khách chưa đăng nhập gõ đường dẫn /wp-admin/, hệ thống bắt buộc phải chuyển hướng họ về biểu mẫu đăng nhập. Hãy sử dụng chính tài khoản quản trị lab sẵn có trong bản Backup để đăng nhập, tuyệt đối không dùng WP-CLI tạo thêm tài khoản mới chỉ để lách bước kiểm tra này. Ngay khi vào được bên trong Dashboard, hãy mở mục Bài viết → Tất cả bài viết để đối chiếu tiêu đề và số lượng bài, sau đó bấm Đăng xuất (Logout) và thử truy cập ngược lại vào trang quản trị xem phiên làm việc đã thực sự đóng chưa.

Form đăng nhập WordPress phục hồi với hai ô tài khoản và mật khẩu trống sau khi khách mở wp-admin

Ảnh chụp lúc 21:41:14 ngày 01/10/2026 (UTC+7), ghi nhận biểu mẫu đăng nhập trống trước khi điền thông tin xác thực qua đường hầm SSH tunnel; hoàn toàn không làm lộ mật khẩu. Bấm vào ảnh để xem kích thước đầy đủ.

Danh sách hai bài xuất bản sau khi đăng nhập giao diện WordPress trên bản phục hồi

Ảnh chụp lúc 21:41:16 ngày 01/10/2026 (UTC+7) ngay sau khi đăng nhập thành công vào giao diện quản trị bằng tài khoản lab hiện hữu: danh sách hiển thị đầy đủ hai bài viết “Bài thử kiểm permalink” và “Chào tất cả mọi người!”. Hình ảnh giữ nguyên pixel gốc kèm logo; lưu ý ảnh này xác nhận danh sách bài viết trong quản trị chứ chưa phải bằng chứng nghiệm thu thư viện ảnh hay các plugin mở rộng.

Thao tác đăng xuất trên giao diện đã xóa sạch cookie xác thực, khiến các lượt truy cập vào khu vực quản trị ngay sau đó bị đẩy ngược về màn hình đăng nhập đúng như kỳ vọng. Kết thúc buổi diễn tập, toàn bộ tiến trình web server tạm, cây thư mục giải nén, cặp Database/user thử nghiệm, phiên trình duyệt và đường hầm SSH đều đã được dọn dẹp sạch sẽ. Mã băm của bốn tệp trong kho Backup cùng hai tệp cấu hình gốc vẫn giữ nguyên vẹn; hai trang web trên lab tiếp tục hoạt động bình thường. Khoảng thời gian chênh lệch giữa các bức ảnh trên tất nhiên không phải là chỉ số RTO, bởi gói Backup đã nằm sẵn trên ổ cứng VPS và chưa tính công đoạn dựng máy chủ mới hay kiểm tra toàn diện mọi tính năng.

Khi gặp lỗi và cách Rollback an toàn

Trong quá trình diễn tập, nếu bạn phát hiện dữ liệu trên trang nguồn bỗng nhiên bị thay đổi bất thường ngay lúc mình đang thao tác trên bản đích, hãy lập tức phanh gấp và ngắt kết nối vhost của bản phục hồi: 99% là tệp wp-config.php trên bản clone của bạn vẫn đang trỏ nhầm về Database của trang nguồn! Hãy rà soát thật kỹ thông tin kết nối Database trước khi dám chạy tiếp bất kỳ lệnh đổi URL nào. Khi một lượt Restore gặp lỗi giữa chừng, hãy lưu lại thông báo lỗi (log) để rút kinh nghiệm rồi khởi tạo một thư mục đích hoàn toàn mới từ bộ Backup nguyên vẹn. Quy trình Rollback của một buổi diễn tập Staging rất đơn giản và an toàn: chỉ cần tắt vhost thử nghiệm, trả cấu hình dịch vụ về trạng thái ban đầu và tuyệt đối không chạm vào dữ liệu của trang nguồn.

Một bẫy kỹ thuật nữa cần lưu ý: nếu bạn đã thực hiện tách riêng tài khoản Database cho bản phục hồi và thu hồi quyền của tài khoản cũ trên Database đó, thì việc chỉ chép đè lại tệp wp-config.php cũ sẽ khiến website báo lỗi kết nối cơ sở dữ liệu ngay lập tức, bởi tài khoản nằm trong file cấu hình cũ đã bị tước quyền truy cập rồi. Bạn luôn phải đồng bộ cả tệp cấu hình lẫn bảng phân quyền Database (GRANT) về cùng một mốc trạng thái, sau đó xác minh lại kết nối và nội dung hiển thị trên cả trang nguồn lẫn trang đích.

Câu hỏi thường gặp

Môi trường thứ hai có cần VPS thứ hai?

Trong khuôn khổ bài diễn tập quy trình này thì bạn chưa cần thuê thêm chiếc VPS thứ hai. Việc tạo một thư mục độc lập, một Database riêng và một vhost lắng nghe nội bộ ngay trên máy lab hiện tại là đủ để rèn luyện kỹ năng thao tác chuẩn xác; tuy nhiên hãy nhớ rằng nếu cả chiếc VPS đó gặp sự cố phần cứng thì cả bản gốc lẫn bản thử đều mất chung.

Vì sao clone tự chuyển về domain cũ?

Hiện tượng bấm vào bản Staging mà trình duyệt cứ tự động nhảy (redirect) về tên miền của trang gốc là do hai giá trị home và siteurl trong bảng wp_options, hoặc hằng số WP_HOME / WP_SITEURL trong wp-config.php (cùng bộ nhớ đệm cache) vẫn đang giữ địa chỉ cũ. Hãy sửa lại chúng, nhưng nhớ chỉ làm điều đó sau khi đã xác minh chắc chắn bạn đang kết nối vào Database đích.

Có được coi checksum khớp là restore thành công?

Tuyệt đối chưa. Checksum khớp mới chỉ chứng minh tệp nén không bị rơi rớt bit nào trong quá trình lưu trữ hay truyền tải. Bạn bắt buộc phải bung tệp, nạp cơ sở dữ liệu vào MariaDB và tự tay kiểm tra các chức năng mà độc giả cũng như quản trị viên thực sự sử dụng hằng ngày thì mới được phép kết luận Restore thành công.

Việc nên làm tiếp

Bước tiếp theo dành cho bạn là hãy tự tạo một bộ Backup trên máy lab có chứa cả bài viết tiếng Việt có dấu lẫn các tệp hình ảnh thực tế, sau đó thực hành Restore vào một thư mục đích độc lập để nghiệm thu từ ảnh gốc, ảnh thu nhỏ (thumbnails), khung đăng nhập cho tới các plugin thiết yếu. Đừng quên khóa chặt đường gửi email ra ngoài trong suốt quá trình thử nghiệm. Hãy bấm giờ đo thử từ lúc bắt đầu kéo bản sao lưu về cho đến khi tích chọn xong bước kiểm tra cuối cùng để đối chiếu với mục tiêu RPO/RTO của dự án. Khi đã làm chủ hoàn toàn quy trình này, hãy tiếp tục đồng hành cùng series WordPress từ A đến Z.

Nguồn và trạng thái kiểm chứng

Tài liệu chính thức được đối chiếu ngày 01/10/2026: cẩm nang sao lưu khôi phục của WordPress và tài liệu lệnh search-replace của WP-CLI. Toàn bộ biên bản thực nghiệm ngày 30/09 cùng các đợt khôi phục và nghiệm thu giao diện ngày 01/10 đều đã được trình bày minh bạch kèm giới hạn phạm vi ở trên. Các khối lệnh mẫu trong bài được biên tập để hướng dẫn thực hành từng bước chứ không chép nguyên văn script tự động của hệ thống kiểm thử; những hạng mục chưa thử nghiệm vẫn cần được bạn kiểm chứng thêm trên hạ tầng riêng.

Tài liệu tham khảo & Kiểm chứng

CẦN KỸ SƯ HỖ TRỢ TRỰC TIẾP? Đang làm theo hướng dẫn nhưng vướng lỗi hệ thống hoặc sợ đụng chạm dữ liệu đang chạy?

Gửi địa chỉ URL qua Zalo để kỹ thuật viên localhost.vn kiểm tra sơ bộ miễn phí trước khi quyết định can thiệp.

Xem bảng dịch vụ
Góc thực chiến localhost.vn

Mọi hướng dẫn đều dựa trên số liệu đo đạc, log thực tế và nguyên tắc "luôn có đường lùi (Snapshot/Backup) trước khi gõ lệnh".

Nguyên tắc biên tập & Minh bạch ↗