Optimization

Cấu hình Varnish cache giữa Nginx và Apache trên Ubuntu 24.04

Vì sao sysadmin cần Varnish trước web server?

Khi traffic website tăng cao, Apache hoặc Nginx có thể bị quá tải vì phải xử lý PHP, database. Đặt Varnish cache trước web server giúp hứng request, trả cache nếu có, chỉ forward đến backend khi cần nội dung động. Kết quả: giảm CPU server, giảm thời gian phản hồi từ 200-500ms xuống còn 1-5ms, tăng khả năng chịu tải gấp 5-10 lần mà không cần nâng cấp VPS.

Bài này hướng dẫn cấu hình Varnish 7.x làm reverse proxy trước Nginx trên Ubuntu 24.04 LTS. Nếu bạn dùng Apache, chỉ cần thay backend port 8080 thành 80 và Nginx thành Apache. Các lệnh đã kiểm tra trên VPS NVMe có IPv4 Việt Nam - bạn có thể chạy VPS Linux thueVPS với full root để làm theo.

Yêu cầu trước khi bắt đầu

  • VPS chạy Ubuntu 24.04 LTS (khuyến nghị thuê VPS tối thiểu 2GB RAM để có đủ bộ nhớ cho cache + web server).
  • User sudo non-root đã cấu hình.
  • Web server Nginx đang chạy ở port 80 (hoặc 8080 nếu chưa có).
  • Firewall (ufw) đã mở port 80, 443 (sau này), 8081 (backup).
  • Kiến thức cơ bản về HTTP header và cache-control.

Kiến trúc tổng quan: Varnish đứng trước Nginx

Luồng request sau khi cài Varnish:

User → Port 80 (Varnish) → Cache HIT? → Trả ngay
                                  ↘ Cache MISS → Port 8080 (Nginx) → PHP-fpm → Response → Varnish lưu cache → Trả cho user

Varnish nghe port 80, Nginx chuyển sang port 8080. Mọi request HTTP đều qua Varnish trước.

Thành phầnPort mặc địnhVai trò
Varnish80Reverse proxy + cache
Nginx8080Web server backend
PHP-fpm9000 (Unix socket)Xử lý PHP

Bước 1 - Cài đặt Varnish từ repo chính thức

Không dùng package mặc định của Ubuntu (thường cũ). Dùng repo Varnish chính thức cho bản mới nhất 7.x.

# Cài curl nếu chưa có
sudo apt update && sudo apt install curl -y

# Thêm repo Varnish
curl -fsSL https://packagecloud.io/varnishcache/varnish73/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/varnish.gpg
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/varnish.gpg] https://packagecloud.io/varnishcache/varnish73/ubuntu/ jammy main" | sudo tee /etc/apt/sources.list.d/varnish73.list

# Cài đặt
sudo apt update
sudo apt install varnish -y

Kiểm tra phiên bản: varnishd -V. Output mong đợi: varnishd (varnish-7.3.x).

Bước 2 - Chuyển Nginx sang port 8080

Varnish cần nghe port 80, nên Nginx phải chạy port khác. Chỉnh sửa file default config của Nginx:

sudo nano /etc/nginx/sites-available/default

Tìm dòng listen 80 default_server; → sửa thành:

listen 8080 default_server;
listen [::]:8080 default_server;

Kiểm tra config và reload:

sudo nginx -t
sudo systemctl reload nginx

Verify: ss -tlnp | grep 8080 → thấy nginx listening ở 8080. Truy cập http://IP_VPS:8080 vẫn thấy trang web (nếu mở port 8080 trên firewall).

Bước 3 - Cấu hình Varnish nghe port 80 và trỏ backend

3a. Cấu hình systemd service

Mặc định Varnish nghe port 6081. Cần sửa để nghe port 80.

sudo nano /lib/systemd/system/varnish.service

Tìm dòng ExecStart chứa -a :6081 → sửa thành:

ExecStart=/usr/sbin/varnishd -a :80 -a localhost:8443,PROXY -f /etc/varnish/default.vcl -s malloc,256m

Giải thích: -a :80 nghe HTTP, malloc,256m dùng 256MB RAM cho cache (tăng nếu VPS có RAM dư: 512m, 1g). Reload:

sudo systemctl daemon-reload
sudo systemctl restart varnish

3b. Cấu hình VCL trỏ backend Nginx

sudo nano /etc/varnish/default.vcl

Xóa nội dung cũ, thêm:

vcl 4.1;

backend default {
    .host = "127.0.0.1";
    .port = "8080";
}

sub vcl_recv {
    # Bỏ qua cache cho request có cookie session (WordPress, Laravel)
    if (req.http.cookie ~ "(wordpress_logged_in|wp-admin|PHPSESSID)") {
        return (pass);
    }
    # Xóa query string không cần thiết trước khi cache
    set req.url = regsub(req.url, "\?utm_[^&]+&?", "?");
    set req.url = regsub(req.url, "\?&", "?");

    # Normalize Accept-Encoding header
    if (req.http.Accept-Encoding) {
        if (req.url ~ "\.(jpg|jpeg|png|gif|ico|webp|css|js|woff|woff2)$") {
            unset req.http.Accept-Encoding;
        }
    }
}

sub vcl_backend_response {
    # Cache file tĩnh lâu (30 ngày)
    if (bereq.url ~ "\.(jpg|jpeg|png|gif|ico|webp|css|js|woff|woff2)$") {
        set beresp.ttl = 30d;
    }
    # Cache trang HTML tĩnh 1 giờ
    if (beresp.http.content-type ~ "text/html") {
        set beresp.ttl = 1h;
    }
    # Tôn trọng header Cache-Control từ backend
    if (beresp.http.Cache-Control ~ "private|no-cache|no-store") {
        set beresp.uncacheable = true;
        return (deliver);
    }
}

sub vcl_deliver {
    # Thêm header để debug cache HIT/MISS
    if (obj.hits > 0) {
        set resp.http.X-Cache = "HIT";
    } else {
        set resp.http.X-Cache = "MISS";
    }
    unset resp.http.Via;
    unset resp.http.X-Varnish;
}

Kiểm tra cú pháp VCL: varnishadm vcl.load default /etc/varnish/default.vcl. Nếu OK, áp dụng: varnishadm vcl.use default.

Restart Varnish: sudo systemctl restart varnish.

Verify: ss -tlnp | grep varnishd → Varnish nghe port 80. Truy cập http://IP_VPS (không port) → web vẫn hiển thị. Thêm header xem cache: curl -I http://IP_VPS → output có X-Cache: MISS (lần đầu). F5 vài lần → X-Cache: HIT.

Bước 4 - Mở port 80 trên firewall

Nếu dùng ufw:

sudo ufw allow 80/tcp
sudo ufw delete allow 8080  # không cần thiết cho public

Kiểm tra: sudo ufw status → port 80 open.

Xử lý lỗi thường gặp

Lỗi: "Could not start varnishd: -a :80: Address already in use"

Nginx vẫn chạy ở port 80. Dừng Nginx trước (hoặc đảm bảo bạn đã chuyển nó sang 8080): sudo systemctl stop nginx, kiểm tra ss -tlnp | grep :80, nếu Nginx còn chạy → sửa config ở Bước 2.

Lỗi: "VCL load failed: Could not read"

Sai cú pháp VCL. Xem lỗi chi tiết: journalctl -u varnish -n 20. Thường là thiếu dấu chấm phẩy hoặc sai tên log. Sửa file, chạy lại varnishadm vcl.load.

Cache toàn bộ trang admin WordPress

Kiểm tra sub vcl_recv: nếu req.http.cookie ~ "wp-admin" không match, sửa regex thành "(wordpress_logged_in|wp-admin|PHPSESSID)". Thêm return (pass) bỏ qua cache.

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

Varnish có cần SSL không?

Varnish không hỗ trợ SSL native. Để chạy HTTPS, đặt Nginx làm SSL terminator ở port 443, rồi forward về Varnish ở port 80 nội bộ (hoặc dùng hitch/haproxy). Cấu hình phức tạp hơn, phù hợp bài riêng.

Nên đặt dung lượng cache malloc bao nhiêu?

VPS 2GB: 256-512MB. VPS 4GB: 512MB-1GB. Không dùng quá 50% RAM system. Nếu cache đầy, Varnish tự động evict object cũ.

Làm sao biết Varnish đang cache HIT hay MISS?

Thêm header X-Cache như trong VCL mẫu. Dùng curl -I http://domain xem output. Lần đầu MISS, lần sau HIT. Công cụ varnishstat cho số liệu chi tiết: varnishstat -1 | grep -E "cache_hit|cache_miss".

Varnish tốt hơn Nginx caching module ở điểm nào?

Varnish chuyên biệt cho caching, có VCL linh hoạt (điều kiện, purging, grace mode). Nginx caching đơn giản hơn, không hỗ trợ grace mode mượt mà. Varnish là lựa chọn hàng đầu cho high-traffic.

Tôi có thể flush toàn bộ cache Varnish không?

Có: varnishadm ban req.url "~" "." (flush tất cả). Hoặc admin trang cho URL cụ thể: varnishadm ban req.url "~" "^/uploads/".

Varnish có chạy được trên VPS Windows không?

Varnish chỉ chạy trên Linux. Nếu bạn dùng VPS Windows, hãy xem giải pháp cache khác hoặc dùng Linux.

Bài viết liên quan

Lưu ý: Bài viết mang tính tham khảo, tổng hợp kiến thức chung. Mỗi hệ thống, hạ tầng và nhu cầu có đặc thù riêng, nên kiểm thử trong môi trường an toàn và tham vấn kỹ sư trước khi triển khai thực tế.