2026年11月12日

2026年11月12日

Thiết lập Cloudflare cho WordPress: nameserver, SSL, IP thật, WAF

Đây là phiên bản được bản địa hóa từ bài viết gốc tiếng Nhật. Đọc bài gốc tiếng Nhật

Việc cài Cloudflare cho WordPress được tiến hành theo thứ tự: (1) thêm site vào Cloudflare và đổi nameserver của tên miền, (2) đặt chế độ mã hóa SSL/TLS là Full (strict), (3) khôi phục IP thật của người truy cập ở phía máy chủ, (4) bảo vệ trang đăng nhập bằng quy tắc tùy chỉnh của WAF. Ngay cả gói miễn phí cũng dùng được CDN, SSL, chống DDoS và quy tắc tùy chỉnh (tối đa 5 quy tắc).

Bài viết này giải thích từng thiết lập và những điểm cần kiểm tra sau khi chuyển. Tên và vị trí các mục trong giao diện Cloudflare có thể thay đổi, nên ở đây nội dung được viết theo tài liệu chính thức (developers.cloudflare.com) tại thời điểm tháng 11/2026.

Những điều cần quyết định trước khi làm

  • Bạn sẽ chuyển việc quản lý DNS sang Cloudflare. Nhà đăng ký tên miền (registrar) không đổi, nhưng việc chỉnh sửa bản ghi DNS sẽ thực hiện trên giao diện của Cloudflare.
  • Đặt các bản ghi DNS của email (như MX) ở chế độ không qua proxy. Cloudflare chỉ xử lý lưu lượng Web (HTTP/HTTPS).
  • Hãy xác nhận origin (máy chủ đặt WordPress) có chứng chỉ SSL hợp lệ. Nếu HTTPS đã dùng được với Let's Encrypt hoặc tương tự thì giữ nguyên là được.
  • Nếu bạn đã bật DNSSEC ở phía registrar, hãy tắt nó trước khi đổi nameserver. Nếu bản ghi DS cũ còn sót lại, việc phân giải tên miền sẽ thất bại.

Bước 1: Thêm site và đổi nameserver

  1. Tạo tài khoản Cloudflare và thêm tên miền trong bảng điều khiển (Dashboard). Có thể chọn gói Free.
  2. Cloudflare đọc các bản ghi DNS hiện tại và liệt kê ra, hãy kiểm tra xem có thiếu bản ghi nào không. Có bản ghi không đọc được, nên hãy so với màn hình quản lý DNS hiện tại và thêm thủ công những bản ghi còn thiếu.
  3. Với bản ghi A (hoặc AAAA, CNAME) của website, hãy bật trạng thái proxy (đám mây màu cam). Với MX và bản ghi A dành cho máy chủ mail, hãy tắt (chỉ DNS, đám mây màu xám).
  4. Cloudflare hiển thị tên của 2 nameserver. Tên có dạng 〇〇.ns.cloudflare.com và được gán riêng cho từng tài khoản. Hãy dùng 2 tên hiện trên màn hình của bạn, không dùng tên ghi trong các bài viết khác.
  5. Trong trang quản lý của registrar, đổi nameserver của tên miền sang 2 tên đó.

Hãy kiểm tra xem đã chuyển xong chưa bằng các lệnh sau. Việc áp dụng có thể mất vài giờ.

# Nameserver đã là 2 tên của Cloudflare chưa
dig NS example.com +short

# Đã đi qua Cloudflare chưa (trả về server: cloudflare và cf-ray)
curl -sI https://example.com | grep -iE '^(server|cf-ray):'

Khi trạng thái của tên miền trên màn hình Cloudflare chuyển sang hoạt động (Active) là việc chuyển đã hoàn tất.

Bước 2: Đặt SSL/TLS là Full (strict)

SSL/TLS của Cloudflare có các chế độ quy định cách mã hóa giữa khách truy cập và Cloudflare, cũng như giữa Cloudflare và origin.

Chế độ Giữa Cloudflare và origin Cách dùng với WordPress
Off Không mã hóa Không dùng
Flexible HTTP (không mã hóa) Không dùng. Là nguyên nhân gây vòng lặp chuyển hướng và mixed content
Full HTTPS (không xác minh chứng chỉ) Giải pháp tạm cho đến khi chuẩn bị xong chứng chỉ
Full (strict) HTTPS (có xác minh chứng chỉ) Hãy chọn chế độ này

Chế độ được đổi trong trang tổng quan SSL/TLS (Overview) của bảng điều khiển Cloudflare. Mặc định "Automatic SSL/TLS" là cơ chế tự chọn chế độ an toàn trong phạm vi origin hỗ trợ. Nếu bạn tự chọn Full (strict), site sẽ không bao giờ chạy ở một chế độ ngoài ý muốn. Chứng chỉ của origin có thể là của cơ quan chứng thực công khai (như Let's Encrypt) hoặc chứng chỉ Origin CA do Cloudflare cấp.

Lý do nên tránh Flexible như sau. Với Flexible, yêu cầu đến origin bằng HTTP, nên WordPress hoặc máy chủ phản hồi "đến bằng HTTP nên chuyển sang HTTPS", và Cloudflare lại tiếp tục lấy từ origin bằng HTTP, tạo thành vòng lặp (trình duyệt hiện ERR_TOO_MANY_REDIRECTS). Với Full (strict), yêu cầu đến origin cũng bằng HTTPS, nên phía WordPress không cần thêm mã nào kiểu xem X-Forwarded-Proto rồi ghi đè $_SERVER['HTTPS'].

Đồng thời hãy xác nhận "Địa chỉ WordPress (URL)" và "Địa chỉ trang web (URL)" trong "Cài đặt" (Settings) → "Chung" (General) của WordPress đã bắt đầu bằng https://. Nếu hình ảnh, v.v. vẫn còn ở http://, hãy xem cách sửa mixed content.

Bước 3: Khôi phục IP thật của người truy cập

Khi đi qua Cloudflare, nguồn kết nối (REMOTE_ADDR) đến máy chủ trở thành địa chỉ IP của Cloudflare. Nếu để nguyên như vậy, nhật ký truy cập, IP của bình luận, plugin giới hạn lượt thử đăng nhập, v.v. sẽ coi mọi khách truy cập đều là IP của Cloudflare. Cloudflare chuyển IP của khách qua header CF-Connecting-IP, nên hãy cấu hình để chỉ tin header đó khi nguồn kết nối là Cloudflare.

Nếu ghi đè REMOTE_ADDR bằng giá trị header mà không kiểm tra nguồn kết nối, người truy cập trực tiếp origin mà không qua Cloudflare có thể tự xưng IP tùy ý bằng header. Vì lý do này, đừng dùng đoạn mã trong các bài viết cũ chỉ "nếu có HTTP_CF_CONNECTING_IP thì gán vào REMOTE_ADDR".

Danh sách địa chỉ IP của Cloudflare được công bố tại https://www.cloudflare.com/ips/. Danh sách có thể thay đổi nên hãy rà soát định kỳ.

Trường hợp dùng Nginx

Dùng ngx_http_realip_module. Liệt kê toàn bộ các dải của Cloudflare trong khối http hoặc khối server.

# Dải IP của Cloudflare (tại thời điểm tháng 11/2026. Xem bản mới nhất tại cloudflare.com/ips)
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 131.0.72.0/22;
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2405:b500::/32;
set_real_ip_from 2405:8100::/32;
set_real_ip_from 2a06:98c0::/29;
set_real_ip_from 2c0f:f248::/32;

real_ip_header CF-Connecting-IP;
sudo nginx -t && sudo systemctl reload nginx

Trường hợp dùng Apache (Debian / Ubuntu)

Dùng mod_remoteip. Tạo /etc/apache2/conf-available/remoteip.conf và liệt kê các dải của Cloudflare trong RemoteIPTrustedProxy.

RemoteIPHeader CF-Connecting-IP
RemoteIPTrustedProxy 173.245.48.0/20 103.21.244.0/22 103.22.200.0/22 103.31.4.0/22
RemoteIPTrustedProxy 141.101.64.0/18 108.162.192.0/18 190.93.240.0/20 188.114.96.0/20
RemoteIPTrustedProxy 197.234.240.0/22 198.41.128.0/17 162.158.0.0/15 104.16.0.0/13
RemoteIPTrustedProxy 104.24.0.0/14 172.64.0.0/13 131.0.72.0/22
RemoteIPTrustedProxy 2400:cb00::/32 2606:4700::/32 2803:f800::/32 2405:b500::/32
RemoteIPTrustedProxy 2405:8100::/32 2a06:98c0::/29 2c0f:f248::/32
sudo a2enmod remoteip
sudo a2enconf remoteip
sudo apache2ctl configtest
sudo systemctl restart apache2

Để ghi IP thật vào nhật ký truy cập, hãy đổi %h thành %a trong LogFormat (combined) của /etc/apache2/apache2.conf.

Trường hợp không đổi được cấu hình máy chủ (wp-config.php)

Nếu bạn không đụng được vào cấu hình của máy chủ Web, như trên dịch vụ hosting dùng chung, hãy thực hiện cùng cách xác định đó trong wp-config.php. Đặt trước dòng require_once ABSPATH . 'wp-settings.php';. Chỉ khi nguồn kết nối nằm trong các dải của Cloudflare thì mới dùng giá trị của CF-Connecting-IP (giá trị hợp lệ là địa chỉ IP).

<?php
// Chỉ khi đi qua Cloudflare mới dùng CF-Connecting-IP làm IP của khách truy cập
$cf_ranges = [
    '173.245.48.0/20', '103.21.244.0/22', '103.22.200.0/22', '103.31.4.0/22',
    '141.101.64.0/18', '108.162.192.0/18', '190.93.240.0/20', '188.114.96.0/20',
    '197.234.240.0/22', '198.41.128.0/17', '162.158.0.0/15', '104.16.0.0/13',
    '104.24.0.0/14', '172.64.0.0/13', '131.0.72.0/22',
    '2400:cb00::/32', '2606:4700::/32', '2803:f800::/32', '2405:b500::/32',
    '2405:8100::/32', '2a06:98c0::/29', '2c0f:f248::/32',
];

function cf_ip_in_range(string $ip, string $cidr): bool
{
    [$net, $bits] = explode('/', $cidr);
    $ip_bin  = inet_pton($ip);
    $net_bin = inet_pton($net);
    if ($ip_bin === false || $net_bin === false || strlen($ip_bin) !== strlen($net_bin)) {
        return false;
    }
    $bits  = (int) $bits;
    $bytes = intdiv($bits, 8);
    if ($bytes > 0 && substr($ip_bin, 0, $bytes) !== substr($net_bin, 0, $bytes)) {
        return false;
    }
    $rest = $bits % 8;
    if ($rest === 0) {
        return true;
    }
    $mask = (0xFF << (8 - $rest)) & 0xFF;
    return (ord($ip_bin[$bytes]) & $mask) === (ord($net_bin[$bytes]) & $mask);
}

if (!empty($_SERVER['HTTP_CF_CONNECTING_IP']) && !empty($_SERVER['REMOTE_ADDR'])) {
    foreach ($cf_ranges as $range) {
        if (cf_ip_in_range($_SERVER['REMOTE_ADDR'], $range)) {
            $visitor = filter_var($_SERVER['HTTP_CF_CONNECTING_IP'], FILTER_VALIDATE_IP);
            if ($visitor !== false) {
                $_SERVER['REMOTE_ADDR'] = $visitor;
            }
            break;
        }
    }
}

Trong wp-config.php đã có sẵn <?php từ đầu, nên đừng chép dòng <?php ở dòng 1, mà hãy dán từ dòng 2 trở đi. Trước khi dán, hãy sao lưu wp-config.php.

Bước 4: Bảo vệ trang đăng nhập bằng quy tắc tùy chỉnh của WAF

Quy tắc tùy chỉnh (custom rules) của WAF Cloudflare tạo được tối đa 5 quy tắc ở gói miễn phí và có thể chọn các hành động khác ngoài Log (Block, Managed Challenge, v.v.). Để tạo, vào trang Security rules trong bảng điều khiển, chọn "Create rule" rồi "Custom rules", chỉ định điều kiện (Field, Operator, Value) và hành động, sau đó "Deploy".

Ví dụ 1: Chỉ mở trang đăng nhập và trang quản trị cho IP của bạn

Đây là ví dụ khi bạn có IP cố định ở nhà hoặc công ty. Viết thành biểu thức như sau (thay 203.0.113.10 và 198.51.100.0/24 bằng IP của bạn).

(http.request.uri.path eq "/wp-login.php" or starts_with(http.request.uri.path, "/wp-admin/"))
and http.request.uri.path ne "/wp-admin/admin-ajax.php"
and not ip.src in {203.0.113.10 198.51.100.0/24}

Hãy đặt hành động là Block. /wp-admin/admin-ajax.php được loại khỏi điều kiện vì các chức năng của trang công khai như biểu mẫu liên hệ và cuộn vô hạn có thể gọi nó khi chưa đăng nhập.

Ví dụ 2: Khi không có IP cố định, lọc theo quốc gia và Managed Challenge

(http.request.uri.path eq "/wp-login.php" or http.request.uri.path eq "/xmlrpc.php")
and not ip.src.country in {"JP"}

Để xác định quốc gia, hãy dùng ip.src.country (mã 2 ký tự theo ISO 3166-1). ip.geoip.country trong các bài viết cũ đã bị khuyến cáo không dùng. Về hành động, ban đầu hãy dùng Managed Challenge, xem trong các sự kiện bảo mật (security events) xem có truy cập hợp lệ nào bị vướng không, rồi nếu cần mới đổi sang Block. Tài liệu của Cloudflare cũng khuyến nghị cách làm này. xmlrpc.php vẫn được dùng khi đăng bài từ Jetpack hoặc ứng dụng điện thoại, nên hãy kiểm tra xem bạn có dùng không rồi mới đưa vào điều kiện.

Giới hạn theo quốc gia chỉ là biện pháp hỗ trợ, có thể bị vượt qua bằng VPN, v.v. Hãy kết hợp với xác thực hai yếu tố và giới hạn số lần đăng nhập. Cách xác định quốc gia ở phía Nginx được giải thích tại Cách giới hạn truy cập theo quốc gia bằng GeoIP2 trong Nginx.

Bước 5: Hành vi cache mặc định và việc xóa cache khi xuất bản

Mặc định, Cloudflare không cache HTML. Những gì được cache là các tệp tĩnh như hình ảnh, CSS, JavaScript, phông chữ, được quyết định theo phần mở rộng. Ngoài ra, các phản hồi có header Set-Cookie cũng không được cache. Vì vậy, nếu không thiết lập gì thêm, trang quản trị và trang đăng nhập sẽ không bị Cloudflare cache.

Nếu muốn cache cả HTML, hãy mở rộng đối tượng bằng Cache Rules, nhưng khi đó cần loại /wp-admin/, /wp-login.php, bản xem trước và nội dung hiển thị cho người dùng đang đăng nhập ra khỏi đối tượng. Nếu loại sai, màn hình dành cho quản trị viên có thể bị hiển thị cho người khác, nên nếu chưa tự tin thì tốt nhất là để nguyên mặc định.

Khi bạn đã thay CSS hoặc hình ảnh mà hiển thị không đổi, hãy xóa (purge) từ phần thiết lập cache trong bảng điều khiển. Nếu muốn tự động xóa mỗi khi xuất bản hoặc cập nhật bài viết, hãy gọi API của Cloudflare. Trước hết, tạo trên Cloudflare một API token chỉ có quyền "Cache Purge", rồi ghi nó cùng ID vùng (Zone ID, hiển thị trên trang tổng quan của tên miền) vào wp-config.php dưới dạng hằng số.

define( 'CF_ZONE_ID', 'ID_VUNG' );
define( 'CF_API_TOKEN', 'API_TOKEN' );

Đặt đoạn mã sau vào functions.php của child theme hoặc một plugin nhỏ tự viết (có thể dùng Code Snippets, v.v.).

<?php
// Khi xuất bản hoặc cập nhật bài viết, xóa cache của bài đó và của trang chủ khỏi Cloudflare
function cf_purge_urls(array $urls): bool
{
    if (!defined('CF_ZONE_ID') || !defined('CF_API_TOKEN')) {
        return false;
    }

    $response = wp_remote_post(
        'https://api.cloudflare.com/client/v4/zones/' . CF_ZONE_ID . '/purge_cache',
        [
            'headers' => [
                'Authorization' => 'Bearer ' . CF_API_TOKEN,
                'Content-Type'  => 'application/json',
            ],
            'body'    => wp_json_encode(['files' => array_values($urls)]),
            'timeout' => 15,
        ]
    );

    if (is_wp_error($response)) {
        error_log('Cloudflare purge failed: ' . $response->get_error_message());
        return false;
    }

    $result = json_decode(wp_remote_retrieve_body($response), true);
    return !empty($result['success']);
}

add_action('publish_post', function (int $post_id): void {
    if (wp_is_post_revision($post_id) || wp_is_post_autosave($post_id)) {
        return;
    }
    cf_purge_urls([get_permalink($post_id), home_url('/')]);
});

publish_post chạy khi một bài viết được xuất bản và khi một bài đã xuất bản được cập nhật. API purge_cache ngoài files để chỉ định URL còn có purge_everything để xóa toàn bộ, nhưng xóa toàn bộ sẽ khiến cả các tệp tĩnh đều phải lấy lại, nên đừng dùng mỗi khi xuất bản bài viết.

Những điều cần kiểm tra sau khi chuyển

  • Kết quả của curl -sI có server: cloudflare và cf-ray, và trình duyệt hiện biểu tượng ổ khóa
  • Đăng nhập được vào trang quản trị, lưu được bài viết và tải được tệp lên thư viện media
  • Bình luận mới và nhật ký truy cập ghi IP của khách truy cập, không phải IP của Cloudflare
  • Email từ biểu mẫu liên hệ vẫn đến nơi (bản ghi MX không bị proxy)
  • Nếu đã tạo quy tắc tùy chỉnh của WAF, hãy mở wp-login.php từ một đường truyền không được cho phép (như mạng di động của điện thoại) và xác nhận hiện Block hoặc challenge

Các sự cố thường gặp

Gặp ERR_TOO_MANY_REDIRECTS

Hãy kiểm tra xem chế độ SSL/TLS có đang là Flexible không. Cài chứng chỉ cho origin và đổi sang Full (strict) là hết.

Không vào được trang quản trị

Có thể điều kiện của quy tắc tùy chỉnh WAF không bao gồm IP hoặc quốc gia của bạn. Hãy tạm vô hiệu hóa quy tắc từ bảng điều khiển Cloudflare, xem trong các sự kiện bảo mật xem bạn vướng quy tắc nào rồi mới sửa biểu thức.

Mọi truy cập đều trông như cùng một IP

Việc khôi phục IP thật ở Bước 3 chưa thành công. Với Nginx, hãy kiểm tra dải của set_real_ip_from và real_ip_header; với Apache, hãy kiểm tra xem remoteip đã được bật chưa.

Tổng kết

  • Đổi nameserver sang 2 tên được gán cho tài khoản của bạn, và không proxy các bản ghi dành cho email như MX
  • SSL/TLS dùng Full (strict). Flexible là nguyên nhân gây vòng lặp chuyển hướng và mixed content
  • IP thật chỉ được khôi phục bằng cách tin CF-Connecting-IP khi nguồn kết nối nằm trong các dải của Cloudflare
  • Trang đăng nhập được lọc theo IP hoặc quốc gia bằng quy tắc tùy chỉnh WAF, ban đầu dùng Managed Challenge để theo dõi
  • HTML mặc định không bị cache. Việc xóa cache khi xuất bản thực hiện bằng API token chỉ có quyền "Cache Purge"

Bài viết liên quan

Tham khảo: Restoring original visitor IPs (Cloudflare), Encryption modes (Cloudflare), Custom rules (Cloudflare WAF), Default cache behavior (Cloudflare)

Có câu hỏi về WordPress? Đơn vị xuất bản trang này ở Nhật Bản và trả lời bằng tiếng Nhật. Liên hệ (tiếng Nhật)

お気軽にご相談ください

お見積りへ お問い合わせへ
▲