Sat. Apr 19th, 2025

Xây dựng CDN của riêng bạn với Nginx mới nhất 2024

By admin Mar 14, 2024
CDn MAp

Vào năm 2020, toàn thế giới đã tạo ra nội dung lên tới 2,5 triệu byte mỗi ngày. Vào năm 2021, lưu lượng truy cập Internet trên toàn cầu đã đạt 30 GB bình quân đầu người so với 10 GB bình quân đầu người vào năm 2016.

Sự gia tăng này đã khiến nhu cầu về CDN càng trở nên quan trọng hơn. Xử lý một lượng lớn trao đổi dữ liệu đòi hỏi một đường trục thích hợp. Không giống như CDN thương mại, CDN riêng cung cấp cho mình toàn quyền kiểm soát nội dung vì mình không chia sẻ máy chủ/nội dung/máy với các trang web khác sử dụng cùng cơ sở hạ tầng.

Động lực sử dụng CDN

Động lực chính của việc sử dụng CDN rất rõ ràng – để đảm bảo tải trang web cũng như nội dung của nó nhanh chóng và đáng tin cậy cho tất cả khách truy cập trên toàn thế giới. Nhưng nếu bạn quan tâm đến hoạt động của các dự án có lưu lượng truy cập hàng tháng lên tới hàng triệu người dùng và lưu lượng truy cập chỉ từ các tệp JS/CSS là hàng chục TB, thì sớm hay muộn bạn cũng sẽ rơi vào tình trạng kết nối internet 1 Gbps của bạn chỉ dừng lại ở mức đầy đủ.

Trang web thường bao gồm nội dung động và tĩnh. Nội dung động thường bao gồm mã HTML được tạo và dữ liệu từ nhiều API khác nhau (thường là REST hoặc GraphQL). Nội dung tĩnh được tạo thành từ các tệp như javascript, kiểu, hình ảnh, phông chữ hoặc âm thanh/video. Một tỷ lệ điển hình cho các dự án của mình là nội dung động chiếm 10% và tĩnh chiếm 90% tổng lượng truyền dữ liệu.

Nếu bạn có số lượng khách truy cập thực sự cao, việc đưa ra quy tắc các tệp tĩnh được lưu vào bộ nhớ đệm trong trình duyệt có giá trị trong một năm sẽ không giúp ích gì nhiều cho bạn. Việc thay đổi nội dung của tệp sau đó yêu cầu tệp có tên mới hoặc một số “phiên bản” nào đó trong tham số truy vấn để buộc trình duyệt tải xuống tệp mới. Nếu bạn phát hành vài ngày một lần, ngay cả khi bạn sử dụng các đoạn JS/CSS thì ít nhất một phần của JS/CSS sẽ được biên dịch lại và mọi khách truy cập đều phải tải xuống.

Sau đó, khi bạn đạt gigabit ở mức cao nhất về lưu lượng truy cập, bạn bắt đầu giải quyết những việc cần làm tiếp theo và do đó tìm kiếm CDN.

Những lợi ích chính của CDN theo quan điểm của mình

  • Tốc độ dành cho khách truy cập toàn cầu — nếu bạn có một dự án được lưu trữ trên máy chủ chỉ ở một quốc gia cụ thể, điều này sẽ làm tăng thời gian tải trang tương ứng với khoảng cách. Vì vậy, càng đi vòng quanh thế giới, màn hình càng chậm. Lý do là độ trễ cao và tốc độ truyền thấp. Nhưng hãy cẩn thận ở đây — nếu bạn có phần lớn khách truy cập đến từ quốc gia địa phương (đối với mình đó là Cộng hòa Séc), hãy đảm bảo rằng nhà cung cấp CDN của bạn cũng có máy chủ (PoP) ở Cộng hòa Séc. Nếu không, tốc độ tải cho người dùng chính của bạn có thể chậm lại sau khi triển khai CDN. Cộng hòa Séc là một quốc gia nhỏ nhưng có các trung tâm dữ liệu và nhà cung cấp kết nối chất lượng HÀNG ĐẦU. Chỉ tải nội dung từ PoP nước ngoài sẽ gây bất lợi cho khách truy cập Séc.
  • Tốc độ dành cho khách truy cập địa phương – tất cả các trình duyệt đều có giới hạn về số lượng yêu cầu đồng thời tối đa trên mỗi địa chỉ IP của máy chủ. Nếu trình duyệt có thể tải nội dung từ nhiều miền và địa chỉ IP khác nhau ( domain sharding ) thì nó sẽ cho phép song song hóa nhiều hơn và nội dung sẽ tải vào trình duyệt nhanh hơn. Điều này đặc biệt quan trọng đối với JS/CSS/hình ảnh và phông chữ là một phần của kết xuất ban đầu của trang. HTTP/2 với tính năng ghép kênh giúp giải quyết vấn đề này rất tốt nhưng chỉ ở một mức độ nhất định. Dựa trên các yêu cầu thực tế/kiểm tra kết xuất, mình kết luận rằng ngay cả với luồng HTTP/2, nơi có hàng tá tệp trong một luồng, kết quả hiển thị trang sẽ chậm hơn so với khi CDN tham gia vào một miền khác ngoài chính trang web đó.
  • Giảm tải cho máy chủ chính — nếu bạn không có CDN, máy chủ chính của bạn và khả năng kết nối của chúng phải xử lý cả yêu cầu nội dung động và yêu cầu dữ liệu tĩnh tương đối tầm thường. Điều này không hiệu quả vì cấu hình máy chủ tối ưu cho nội dung động hơi khác so với việc xử lý các tệp tĩnh.
  • Tối ưu hóa nội dung – CDN tốt cũng cung cấp các công cụ để tối ưu hóa dữ liệu/nhị phân của nội dung tĩnh. Kết quả là, ít dữ liệu được truyền đi hơn và các trang tải nhanh hơn (nén brotli, hình ảnh WebP hoặc AVIF).
  • Tiết kiệm chi phí — mặc dù từ lâu bạn đã có thể nhận được đường truyền “dày” gần như không giới hạn tới các máy chủ chính của mình, nhưng bước nhảy vọt khá mạnh mẽ — tại sao phải trả 10 Gbit, khi 1 Gbit là đủ cho mình trong 90% thời gian?
  • Đơn giản hóa vòng đời của DevOps – nếu cấu hình của máy chủ tệp/web và ứng dụng để có hiệu suất và bảo mật tối đa được tinh chỉnh thì cần phải có tất cả các số liệu có thể có từ hoạt động thực tế. Nếu lưu lượng truy cập cho nội dung động và nội dung tĩnh được tách biệt hoàn toàn thì số liệu thống kê sẽ rõ ràng hơn. Do đó, có thể đưa ra quyết định tốt hơn và tối ưu hóa các thông số bảo mật và hiệu suất được điều chỉnh chính xác cho khối lượng công việc cụ thể.

Xây dựng CDN với Nginx

Trong bài viết này mình sẽ sử dụng một số công nghệ của và  nhà cung cấp sau:

  • Vinahost: Đây là nhà cung cấp tên miền uy tín và sử dụng hệ thống DNS hiện đại với khả năng Failed Over và GeoDNS giúp DNS của bạn luôn phân giải được IP của POP gần nhất đối với bạn.
  • CS Vinahost : Hệ thống Cloud 2.0 cỉa Vinahost giúp bạn dễ dang setup Server nhanh chóng chỉ vài cái click chuột. Phần cứng mạnh mẽ với IO cao sẽ giúp máy chủ nhanh hơn.
  • Nginx: Máy chủ Web Super Cool phục vụ mọi mục đích.

Đầu tiên chúng ta sẽ review qua mô hình CDN

CDN-topology

Trong mô hình ta sẽ thấy hệ thống bao gồm 3 phần :

  • ProDNS : hệ thống quản lý DNS 2.0 của Vinahost giúp cân bằng tải trên chính DNS. Giúp tên miền luôn được phân giải đến IP của POP gần nhất. Giải quyết được vấn đề Anycast thường được dùng trong hệ thống CDN yêu cầu hạ tầng lớn.
  • POP : đây là 2 POP CDN cho hướng quốc tế và cho hướng trogn VietNam chúng ta sẽ setup Nginx và cấu hình CDN trên 2 server này.
  • Backend : Đây là server gốc Origin để CDN có thể craw hình ảnh và lưu trữ chúng trong CDN.

Bây giờ chúng ta đã chuẩn bị đầy đủ các server cần thiết cho hệ thống. Tiếp theo chúng ta sẽ tiến hành setup từng thành phần trong hệ thống.

Đầu tiên ta cần cấu hình DNS cho tên miền

Hệ thống ProDNS tại Vinahost cho phép chúng ta kết hợp giữa failover và routing đến IP gần nhất.

Ta cần setup theo như hướng dẫn của Vinahost. Tại đây mình sẽ dùng 2 IP một đặt tại Việt Nam và một ở Singapore như sau:

DNS-setup

Tiếp theo chúng ta sẽ cấu hình Server Nginx để làm POP

Trước khi tiến hành cấu hình Nginx ta cần cấu hình kernel để đảm bảo có thể chịu được tối đa cường độ request của CDN.

Cấu hình Kernel được tôi đề xuất sử dụng như sau:


				
					fs.aio-max-nr = 524288 

fs.file-max = 611160 

kernel.msgmax = 131072 

kernel.msgmnb = 131072 

kernel. panic = 15 

kernel.pid_max = 65536 

kernel.printk = 4 4 1 7 

net.core.default_qdisc = fq 

net.core.netdev_max_backlog = 262144 

net.core.optmem_max = 16777216 

net.core.rmem_max = 16777216 

net.core.somaxconn = 65535 

net.core.wmem_max = 16777216 

net.ipv4.conf.all.accept_redirects = 0 

net.ipv4.conf.all.log_martians = 1 

net.ipv4.conf.all.rp_filter = 1 

net.ipv4.conf.all.secure_redirects = 0 

net.ipv4.conf.all.send_redirects = 0 

net.ipv4.conf.default.accept_redirects = 0 

net.ipv4.conf.default.accept_source_route = 0 

net.ipv4.conf.default.rp_filter = 1 

net.ipv4.conf.default.secure_redirects = 0 

net.ipv4.conf.default.send_redirects = 0 

net.ipv4.ip_forward = 0 

net.ipv4.ip_local_port_range = 1024 65535 

net.ipv4.tcp_congestion_control = bbr 

net.ipv4.tcp_fin_timeout = 10 

net.ipv4.tcp_keepalive_intvl = 10 

net.ipv4.tcp_keepalive_probes = 5 

net.ipv4.tcp_keepalive_time = 60 

net.ipv4.tcp_low_latency = 1 

net.ipv4.tcp_max_orphans = 10000 

net.ipv4.tcp_max_syn_backlog = 65000 

net.ipv4.tcp_max_tw_buckets = 1440000 

net.ipv4.tcp_moderate_rcvbuf = 1 

net.ipv4.tcp_no_metrics_save = 1 

net.ipv4.tcp_notsent_lowat = 16384 

net.ipv4.tcp_rfc1337 = 1 

net.ipv4.tcp_rmem = 4096 87380 16777216 

net.ipv4.tcp_sack = 0 

net.ipv4.tcp_slow_start_after_idle = 0 

net.ipv4.tcp_synack_retries = 2 

net.ipv4.tcp_syncookies = 1 

net.ipv4.tcp_syn_retries = 2 

net.ipv4.tcp_timestamps = 0 

net.ipv4.tcp_tw_reuse = 1 

net.ipv4.tcp_window_scaling = 0 

net.ipv4.tcp_wmem = 4096 65536 16777216 

net.ipv6.conf.all.disable_ipv6 = 1 

net.ipv6.conf.default.disable_ipv6 = 1 

net.ipv6.conf.lo.disable_ipv6 = 1 

vm.dirty_background_ratio = 2 

vm.dirty_ratio = 60 

vm.max_map_count = 262144 

vm.overcommit_memory = 1 

vm.swappiness = 1
				
			

Tiếp theo chúng ta sẽ tiến hành cấu hình Nginx để có thể sử dụng.

Đầu tiên ta cần hiểu được Cache của Nginx đây là tính năng chính để có thể setup CDN

Bộ đệm là chức năng chính của CDN, vì vậy mình khuyên bạn nên hiểu rõ trước khi cấu hình:

  • Hãy xem hướng dẫn Bộ nhớ đệm hiệu suất cao . Đối với bộ đệm proxy, hãy nghiên cứu và hiểu kỹ tất cả các lệnh proxy_cache*_ cũng như các tham số của chúng. Bắt đầu với proxy_cache_path và các thuộc tính cấp độ , key_zone , _inactive_or max_size . Ví dụ: đối với các PoP phụ từ xa, bạn có thể không hoạt động trong nhiều tuần hoặc nhiều tháng — trình quản lý bộ nhớ đệm cũng sẽ giữ nội dung chưa được truy cập lâu hơn, do đó làm tăng hiệu quả tăng tốc của CDN và tỷ lệ truy cập bộ nhớ đệm ngay cả đối với các PoP từ đó nội dung của các URL cụ thể không được tải xuống thường xuyên.
  • Đặt lệnh proxy_cache_valid một cách tối ưu , lệnh này ảnh hưởng đến thời gian lưu trữ mã HTTP. Nếu bạn quyết định lưu các mã lỗi vào bộ đệm, ví dụ: 400 Yêu cầu Không hợp lệ , thì chỉ lưu chúng vào bộ đệm trong một khoảng thời gian rất ngắn để giảm thiểu tác động của việc “ngộ độc bộ đệm” có thể xảy ra.
  • Nếu bạn không muốn bản gốc xem xét “kiểm soát bộ đệm” của nó thông qua các tiêu đề phản hồi khi lưu vào bộ đệm, bạn có thể sử dụng proxy_ignore_headers và bỏ qua các tiêu đề Cache-Control , _Expires_ hoặc Vary thông thường .
  • Ngoài ra, hãy chú ý đến proxy_cache_use_stale, điều này ảnh hưởng đến cách hoạt động của bộ đệm nếu nguồn gốc không có sẵn. Mình quyết định rằng nếu tình cờ bản gốc bị hỏng và bộ nhớ đệm đã hết hạn, mình vẫn sẽ trả lại nội dung gốc cho khách truy cập. Điều này sẽ khuyến khích tính sẵn sàng cao. Đồng thời thiết lập cập nhật để tải nội dung của khách truy cập ngay lập tức từ bộ đệm sau khi hết hạn (không cần đợi bản gốc), nhưng cập nhật nội dung ngay lập tức từ bản gốc ở chế độ nền cho khách truy cập trong tương lai. Điều này giúp loại bỏ ảnh hưởng của việc thỉnh thoảng bị chậm lại, đôi khi khách truy cập “bị cuốn theo” bởi nhu cầu cập nhật nội dung đã hết hạn của một URL nhất định trong CDN.
  • Quyết định những gì cần đặt trong proxy_cache_key . Ví dụ: bạn có muốn đưa một chuỗi truy vấn có thể có vào khóa bộ đệm, khóa này thường được sử dụng để “phiên bản” các tệp và ngăn chặn bộ đệm của phiên bản gốc của tệp không?
  • Kích hoạt proxy_cache_lock để giữ cho việc lấp đầy/giữ bộ đệm ở mức tối ưu ngay cả với khả năng song song hóa cao và quyết định cách đặt proxy_cache_min_uses .

Ngoài ra, hãy xem xét các mẹo và cài đặt sau ảnh hưởng đến hiệu suất Nginx:

 

  • Nếu nền tảng của bạn cho phép, hãy thiết lập sử dụng epool . Nếu bạn có kernel 4.5+, nó sẽ sử dụng EPOLLEXCLUSIVE .
  • Để nghe chỉ thị của nút chính trong CDN của bạn ( cdn.company.com ), hãy sử dụng reuseport để các yêu cầu tới từng nhân viên Nginx được phân phối bởi hạt nhân, điều này hiệu quả hơn nhiều lần . Đối với chỉ thị listen, hãy nghiên cứu thêm các tham số backlog và fastopen . Bạn cũng có thể kích hoạt deferred để yêu cầu chỉ đến Nginx khi máy khách thực sự nhận được dữ liệu đầu tiên, điều này có thể giải quyết tốt hơn một số loại tấn công DDoS.
  • Kích hoạt http2 theo lệnh listen và luôn giữ một bộ ssl_ciphers an toàn (đối với các phiên bản trình duyệt mà bạn muốn hỗ trợ).
  • Nếu bạn có đủ khả năng để làm như vậy với các trình duyệt được hỗ trợ, chỉ hỗ trợ TLSv1.2 và TLSv1.3 .
  • Bộ xử lý máy chủ CDN sẽ chủ yếu được tải bằng cách nén gzip/brotli và giao tiếp SSL/TLS. Đặt ssl_session_cache để giảm thiểu bắt tay SSL/TLS. Mình khuyên bạn nên chia sẻ để bộ đệm được chia sẻ giữa tất cả các nhân viên. Ví dụ: kích thước bộ đệm là 50 MB, sẽ phù hợp với khoảng 200.000 phiên trong bộ đệm. Để giảm thiểu số lần bắt tay SSL/TLS, bạn có thể tăng ssl_session_timeout . Nếu bạn không muốn sử dụng bộ đệm SSL trên máy chủ, hãy bật ssl_session_tickets để duy trì bộ đệm phiên hoạt động ít nhất là trong trình duyệt.
  • Đối với cài đặt SSL, hãy kích hoạt 0-RTT trên TLSv1.3 ( ssl_early_data on ) để giảm đáng kể độ trễ, nhưng hãy hiểu và cân nhắc việc Phát lại tấn công .
  • Nếu bạn muốn đạt được TTBF tối thiểu (với chi phí tải cao hơn khi truyền các tệp lớn), hãy nghiên cứu và đặt ssl_buffer_size và http2_chunk_size ở mức thấp hợp lý . Ngoài ra, hãy triển khai bản vá Cloudflare cho Nginx, hỗ trợ cài đặt động – chỉ cần google lệnh ssl_dyn_rec_size_lo .
  • Ngoài ra, hãy tập trung vào việc tìm hiểu và thiết lập KeepAlive cả ở phía máy khách và tuyến thượng nguồn — điều này sẽ giúp hợp lý hóa hoạt động liên lạc với các máy chủ gốc. KeepAlive HTTP/2 được điều chỉnh bởi chỉ thị http2_idle_timeout (mặc định: 3 phút), hãy xem thêm http2_recv_timeout . Việc duy trì các kết nối mở trong thời gian dài không cần thiết sẽ làm giảm đáng kể số lượng khách truy cập mà bạn có thể phục vụ. Nó cũng ảnh hưởng đến mức độ lớn của một cuộc tấn công DDoS mà bạn có thể chống lại. Bạn nên hiểu cách hoạt động của tính năng theo dõi kết nối (cả trên Linux và có thể cả trên bộ định tuyến khi máy chủ ở phía sau NAT), nó liên quan như thế nào đến cài đặt limit_conn và cách nó hoạt động nói chung nếu bạn có hàng trăm nghìn khách truy cập vào máy chủ của bạn hoặc đang bị tấn công DDoS trên L7.
  • Nếu bạn cần phát hiện sự thay đổi trong địa chỉ IP của bản gốc và bạn không có Nginx Plus trả phí với thuộc tính phân giải trên máy chủ ngược dòng, bạn chỉ có thể sử dụng proxy_pass: https://www.myorigin.com;thay vì xác định ngược dòng. Ở chế độ này, proxy_pass giám sát TTL trong DNS miền và cập nhật (các) địa chỉ IP nếu cần.
  • Ngoài ra, hãy nghiên cứu các chỉ thị Lingling_close , Lingling_time và Lingling_timeout để xác định tốc độ đóng các kết nối không hoạt động. Để có khả năng chống lại các cuộc tấn công tốt hơn, việc giảm thời gian mặc định là điều hợp lý. Tuy nhiên, đối với các kết nối HTTP/2, các lệnh kéo dài_* chỉ được áp dụng kể từ Nginx 1.19.1.
  • Tăng ULIMIT trong /etc/default/nginx và cũng đặt LimitNOFILE cao hơn trong /etc/systemd/system/nginx.service.d/nginx.conf .
  • Các sendfile , tcp_nopush và tcp_nodelay cũng giúp xử lý file và yêu cầu một cách nhanh chóng. Để ngăn các máy khách có kết nối nhanh tải xuống các tệp lớn sử dụng hết toàn bộ quy trình của nhân viên, hãy đặt sendfile_max_chunk một cách hợp lý.
  • Nếu bạn đang xử lý các tệp rất lớn và nhận thấy các yêu cầu khác bị chậm, hãy cân nhắc sử dụng aio . Đảm bảo đặt lệnh directio một cách thích hợp, xác định kích thước tối đa của tệp sẽ vẫn được gửi qua sendfile và các tệp lớn hơn qua aio. Mình nhận thấy 4MB là giá trị tối ưu, do đó tất cả JS/CSS/phông chữ và hầu hết hình ảnh đều được xử lý thông qua tệp gửi và thường là từ bộ đệm FS, do đó, cũng không có IO nào thực hiện việc này.
  • Đồng thời xem các chỉ thị xung quanh open_file_cache . Với cài đặt tối ưu và đủ RAM, bạn sẽ có IOPS gần như bằng 0, ngay cả khi bạn đang xóa hàng trăm Mbps.
  • Để xử lý số lượng lớn khách truy cập đồng thời và bảo vệ bạn khỏi các cuộc tấn công, hãy giảm client_max_body_size , client_header_timeout , client_body_timeout và send_timeout theo nguyên tắc.
  • Đối với cài đặt nhật ký truy cập, hãy nghiên cứu các tham số bộ đệm và xóa để giảm thiểu IOPS liên quan đến việc ghi nhật ký. Xin lưu ý rằng điều này cũng sẽ khiến nhật ký không được ghi 100% theo trình tự thời gian. Nhật ký truy cập lý tưởng nhất nên được lưu trữ trên một đĩa khác với dữ liệu được lưu trong bộ nhớ cache.
  • Đối với các phiên bản ngược dòng, bạn có thể sử dụng cân bằng tải (nếu bản gốc có thể được truy cập qua nhiều địa chỉ IP) và các thuộc tính trọng số dự phòng . Trong phiên bản hiện tại, thuộc tính max_conns hữu ích , vốn chỉ có ở phiên bản trả phí trong một thời gian dài, hiện đã có sẵn miễn phí.
  • Nếu bạn cũng muốn có một số dạng logic tự động thử lại (đối với trường hợp nguồn gốc không có sẵn trong thời gian ngắn), bạn có thể giải quyết nó chẳng hạn bằng cách sử dụng nhiều máy chủ ngược dòng cho cùng một bản gốc, nhưng ở giữa chúng đặt một vhost ngắn Mã Lua sẽ cung cấp chế độ ngủ giữa các yêu cầu thử lại.
  • Sử dụng thiết lập trình phân giải tùy chỉnh và xem xét sử dụng dnsmasq cục bộ làm trình phân giải chính.
  • Tìm hiểu cách Trình quản lý bộ đệm hoạt động trong Nginx, nó bắt đầu hoạt động đặc biệt khi bộ đệm đầy.
  • Không phải mọi thứ đều có thể được đề cập ở đây, nhưng các thuộc tính khác đều có tác động đến hành vi của proxy và bộ đệm, mình khuyên bạn nên nghiên cứu và thiết lập: proxy_buffering, proxy_buffer_size, proxy_buffers, proxy_read_timeout, out_buffers, reset_timedout_connection .
  • Nếu bạn sẽ sử dụng các mô-đun động với Nginx (trong trường hợp của mình là nén brotli và WAF), với mỗi lần nâng cấp Nginx, bạn phải biên dịch lại tất cả các mô-đun theo phiên bản Nginx mới. Nếu bạn không làm điều này, Nginx sẽ không khởi động sau khi nâng cấp do xung đột chữ ký với các mô-đun *.so. Do đó, tốt hơn hết bạn nên tự động hóa toàn bộ quá trình nâng cấp Nginx, vì bạn sẽ gặp phải Nginx bị hỏng khi nâng cấp, ví dụ như apt. Một phần của quá trình tự động hóa này sẽ bao gồm việc sử dụng tùy chọn thực hiện nâng cấp Nginx một cách nhanh chóng trong đó Nginx tiếp tục chạy phiên bản cũ (từ bộ nhớ) và đồng thời chạy (hoặc ít nhất là cố gắng) phiên bản mới từ tệp nhị phân hiện tại và các mô-đun. Điều này sẽ đảm bảo rằng bạn không mất một yêu cầu nào trong quá trình nâng cấp, ngay cả khi Nginx mới không chạy sau khi nâng cấp vì lý do nào đó. Toàn bộ quá trình này ở hầu hết các bản phân phối ở dạng tập lệnh init theo hành động nâng cấp , tức là nâng cấp dịch vụ nginx . Để ngăn chặn các nâng cấp Nginx không mong muốn khi nâng cấp các gói trên toàn cầu, hãy sử dụng apt-mark hold/unhold nginx .

Tùy thuộc vào nội dung và hành vi của bản gốc mà bạn muốn hỗ trợ, bạn sẽ cần nghiên cứu và có thể gỡ lỗi hoạt động của bộ đệm CDN đối với tiêu đề Kiểm soát bộ đệm hoặc, có lẽ khá cơ bản, tiêu đề Vary . Ví dụ: nếu nguồn gốc cho biết trong phản hồi Vary: User-Agent , thì khóa bộ đệm phải bao gồm tác nhân người dùng của máy khách, nếu không, bạn có thể dễ dàng trả lại HTML đã lưu trong bộ nhớ đệm cho phiên bản di động cho ai đó trên máy tính để bàn. Nhưng điều đó phụ thuộc vào kịch bản và loại nội dung bạn muốn/không muốn hỗ trợ. Việc hỗ trợ các tình huống này thường đòi hỏi rất nhiều công sức và nó cũng làm giảm hiệu quả của bộ nhớ đệm. Thông thường, bạn sẽ không thể thực hiện được bằng các lệnh Nginx gốc và sẽ phải xử lý một số tình huống bằng tập lệnh Lua.

Cấu hình Nginx mẫu

Dưới đây, mình đã chuẩn bị một cấu hình cơ bản trung bình mẫu của Nginx, trong ví dụ mô hình này không thực hiện proxy ngược trước toàn bộ miền nhưng cung cấp điểm cuối CDN

Các cài đặt đặc biệt khác nhau ở cấp độ xác định cho từng vị trí/nguồn gốc, bởi vì bạn có thể muốn các khóa bộ đệm, tính hợp lệ của bộ đệm, giới hạn, bỏ qua cookie, có/không hỗ trợ WebP hoặc A Các cài đặt đặc biệt khác nhau ở cấp độ xác định cho từng vị trí/nguồn gốc, bởi vì bạn có thể muốn các khóa bộ đệm, tính hợp lệ của bộ đệm, giới hạn, bỏ qua cookie, có/không hỗ trợ WebP hoặc AVIF, xác thực tham chiếu, cài đặt liên quan đến CORS hoạt động khác nhau, hoặc có thể sử dụng mô-đun lát cắt, trong đó bạn phải lưu mã 206 vào bộ đệm và khóa bộ đệm cũng phải chứa $slice_range . Tương tự, đối với một số nguồn gốc, bạn có thể muốn bỏ qua hoàn toàn các tiêu đề Kiểm soát bộ đệm và lưu vào bộ nhớ đệm mọi thứ vào một thời điểm cố định hoặc các đặc tính khác của mỗi nguồn gốc.

Cấu hình cũng chứa nhiều thư mục hoặc tệp gốc khác nhau — tất nhiên những thư mục hoặc tệp này phải được thiết lập bằng tính năng tự động hóa mà bạn đang sử dụng để đưa nguồn gốc mới vào CDN của mình. Vì vậy, hãy thực sự coi đây là hướng dẫn về cách lấy và thiết lập các chức năng khác nhau.VIF, xác thực tham chiếu, cài đặt liên quan đến CORS hoạt động khác nhau, hoặc có thể sử dụng mô-đun lát cắt, trong đó bạn phải lưu mã 206 vào bộ đệm và khóa bộ đệm cũng phải chứa $slice_range . Tương tự, đối với một số nguồn gốc, bạn có thể muốn bỏ qua hoàn toàn các tiêu đề Kiểm soát bộ đệm và lưu vào bộ nhớ đệm mọi thứ vào một thời điểm cố định hoặc các đặc tính khác của mỗi nguồn gốc.

Cấu hình cũng chứa nhiều thư mục hoặc tệp gốc khác nhau — tất nhiên những thư mục hoặc tệp này phải được thiết lập bằng tính năng tự động hóa mà bạn đang sử dụng để đưa nguồn gốc mới vào CDN của mình. Vì vậy, hãy thực sự coi đây là hướng dẫn về cách lấy và thiết lập các chức năng khác nhau.

 
				
					worker_processes 4;
worker_rlimit_nofile 100000;
pcre_jit on;
 events {
  use epoll;
  worker_connections 16000;  
multi_accept on;
}
 http { 
  # IP whitelist to which no conn/rate restrictions should be applied  
geo $ip_whitelist {    
 default        0;   
 127.0.0.1      1;  
 10.225.1.0/24  1;
 }  
map $ip_whitelist $limited_ip {
    0  $binary_remote_addr;
    1  "";  }   
limit_conn_zone $limited_ip zone=connsPerIP:20m; 
limit_conn connsPerIP 30;  limit_conn_status 429;  
limit_req_zone $limited_ip zone=reqsPerMinutePerIP:50m rate=500r/m;  
limit_req zone=reqsPerMinutePerIP burst=700 nodelay;  
limit_req_status 429;   
client_max_body_size 64k;  
client_header_timeout 10s;  
client_body_timeout 10s;  
client_body_buffer_size 16k;  
client_header_buffer_size 4k;   
send_timeout 10s;  
connection_pool_size 512;  
large_client_header_buffers 8 16k;  
request_pool_size 4k;   
http2_idle_timeout 60s;  
http2_recv_timeout 10s; 
http2_chunk_size 16k;   
server_tokens off;  
more_set_headers "Server: My-CDN";   
include /etc/nginx/mime.types;  
variables_hash_bucket_size 128;  
map_hash_bucket_size 256;   
gzip on;  gzip_static on; # searches for the *.gz file and returns it directly from disk (compression is provided by our extra process in the background)  
gzip_disable "msie6";  
gzip_min_length 4096;  
gzip_buffers 16 64k;  
gzip_vary on;  
gzip_proxied any;  
gzip_types image/svg+xml text/plain text/css application/json application/x-javascript application/javascript text/xml application/xml application/xml+rss text/javascript text/x-component font/truetype font/opentype image/x-icon;
gzip_comp_level 4;
brotli on;  
brotli_static on; # searches for the *.br file and returns it directly from the disk (compression is provided by our extra process in the background)  brotli_types text/plain text/css application/javascript application/json image/svg+xml application/xml+rss;  
brotli_comp_level 6;   
output_buffers 1 32k;  
postpone_output 1460;   
sendfile on;  
sendfile_max_chunk 1m;  
tcp_nopush on;  
tcp_nodelay on;   
keepalive_timeout 10 10;  
ignore_invalid_headers on;  
reset_timedout_connection on;   
open_file_cache          max=50000 inactive=30s;
open_file_cache_valid    10s;
open_file_cache_min_uses 2;
open_file_cache_errors   on;
proxy_buffering           on;
proxy_buffer_size         16k;  
proxy_buffers             64 16k;  
proxy_temp_path           /var/lib/nginx/proxy;  
proxy_cache_min_uses      2;   
proxy_ignore_client_abort on;  
proxy_intercept_errors    on;  
proxy_next_upstream       error timeout invalid_header http_500 http_502 http_503 http_504;  
proxy_redirect            off;  
proxy_connect_timeout     60;  
proxy_send_timeout        180;  
proxy_cache_lock          on;  
proxy_read_timeout        10s; 
# setting up trusted IP subnets to respect X-Forwarded-For header (for multi-level proxy setup)  
set_real_ip_from          127.0.0.1/32;  
set_real_ip_from          10.1.2.0/24;  
real_ip_header            X-Forwarded-For;  
real_ip_recursive         on;   ############################################################################  ## Example configuration for:                                             ##  ## https://cdn.mycompany.com/myorigin.com/* -> https://www.myorigin.com/* ##  ############################################################################   
upstream up_www_myorigin_com {
    server www.myorigin.com:443 max_conns=50;
    keepalive 20;
    keepalive_requests 50;
    keepalive_timeout 5s;  }
proxy_cache_path /var/lib/nginx/tmp/proxy/www.myorigin.com levels=1:2 keys_zone=cache_www_myorigin_com:20m inactive=720h max_size=10g;
server {
     server_name cdn.company.com;
     listen lan-ip:443 ssl default_server http2 reuseport deferred backlog=32768;
    ssl_prefer_server_ciphers on;
    ssl_ciphers EECDH+AESGCM:EDH+AESGCM;
    ssl_certificate /etc/nginx/ssl/cdn.company.com.nginx-bundle.crt;
    ssl_certificate_key /etc/nginx/ssl/cdn.company.com.key;
    ssl_session_cache shared:SSL_cdn_company_com:50m;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_dhparam /etc/ssl/webserver_dhparams.pem;
    ssl_early_data on;
    lingering_close on;
    lingering_time 10s;
    lingering_timeout 5s;
    resolver 127.0.0.1; # dnsmasq with logging to get an idea of the DNS traffic that Nginx is doing     ...     
    location ~* ^/myorigin\.com/(.+\.(css|js|jpg|jpeg|png|gif|ico))$ {
      set $origin_uri "/$1$is_args$args";
      root /var/www/myorigin.com;
      access_log  /var/log/nginx/www.myorigin.com/ssl.access.log main buffer=4k flush=5m;
      error_log   /var/log/nginx/www.myorigin.com/ssl.error.log notice;
      if ($request_method !~ ^(GET|HEAD|OPTIONS)$ ) {
        more_set_headers "Content-Type: application/json";
        return 405 '{"code": 405, "message": "Method Not Allowed"}';
      }
      more_clear_headers "Strict-Transport-Security";
      more_set_headers "Strict-Transport-Security: max-age=31536000";
      more_set_headers "X-Content-Type-Options: nosniff";
      more_set_headers 'Link: <https://www.myorigin.com$origin_uri>; rel="canonical"';
       expires 1y; # enforce caching in browsers for 1 year (use only consciously, if you are sure that when you change the content of the file on the original, the URL will also change)
       modsecurity on;
       modsecurity_rules_file /etc/nginx/modsecurity/myorigin.com.conf;       # for requests that fall under CORS (e.g. fonts) we allow to load content only from selected domains      
       set $headerCorsAllowOrigin "";
        if ($http_origin ~ '^https?://(localhost|cdn\.company\.com|www\.myorigin\.com)') {
           set $headerCorsAllowOrigin "$http_origin";
       }
        if ($request_method = 'OPTIONS') {
          more_set_headers "Access-Control-Allow-Origin: $headerCorsAllowOrigin";
          more_set_headers "Access-Control-Allow-Methods: GET, HEAD, OPTIONS";
          more_set_headers "Access-Control-Max-Age: 3600";
          more_set_headers "Content-Length: 0";
          return 204;
      }       # we allow to load content only from the original domain (e.g. it prevents displaying our images on foreign domains) valid_referers none blocked server_names *.myorigin.com;
      if ($invalid_referer) {
          more_set_headers "Content-Type: application/json";
          return 403 '{"code": 403, "message": "Forbidden Resource - invalid referer"}';
      }
       set $webp "";
      set $file_for_webp "";
      if ($http_accept ~* webp) {
          set $webp "A";      }
      if ($request_filename ~ (.+\.(png|jpe?g))$) {
          set $file_for_webp $1;      }
      if (-f $file_for_webp.webp) {
          set $webp "${webp}E";      }
      if ($webp = AE) {
          rewrite ^/(.+)$ /webp/$1 last;      }
     proxy_cache cache_www_myorigin_com; 
     proxy_cache_key "$request_uri"; # we don't need a schema or a host, because we store in per-origin cache and support only HTTPS
     proxy_cache_use_stale error timeout invalid_header updating http_429 http_500 http_502 http_503 http_504;
     proxy_read_timeout 20s;
     proxy_cache_valid 200              720h; 
     proxy_cache_valid 301              4h; 
     proxy_cache_valid 302              1h; 
     proxy_cache_valid 400 401 403 404  30s; 
     proxy_cache_valid 500 501 502 503  30s; 
     proxy_cache_valid 429              10s;        # due to keep-alive on origins 
     proxy_http_version 1.1; 
     proxy_set_header Connection ""; 
     proxy_set_header "Via" "My-CDN"; 
     proxy_set_header "Early-Data" $ssl_early_data; # for the ability to detect Replay attack on the application level 
     proxy_set_header Accept-Encoding ""; # we always want to receive and cache RAW content from the origin, because we have a process for preparing static *.gz and *.br versions 
     proxy_set_header        Host                    www.myorigin.com; 
     proxy_set_header        X-Forwarded-For         $remote_addr; 
     proxy_set_header        X-Forwarded-Host        $host:$server_port; 
     proxy_set_header        X-Forwarded-Server      $host; 
     proxy_set_header        X-Forwarded-Proto       $scheme; 
     if (-f $request_filename) {
          more_set_headers "X-Cache: HIT";      }
     if (!-f $request_filename) { 
         proxy_pass https://up_www_myorigin_com$origin_uri;      }     }
     # internal location for webp    
   location ~* ^/webp(/myorigin\.com/(.*))$ {
      internal;      root /var/www/myorigin.com;
      set $origin_uri "/$1$is_args$args"; 
      access_log /var/log/nginx/www.myorigin.com/ssl.access.webp.log main buffer=4k flush=5m;
      expires 366d;      more_set_headers 'Link: <https://www.myorigin.com$origin_uri>; rel="canonical"'; 
      more_clear_headers 'Vary';      more_set_headers "Vary: Accept"; 
      more_set_headers "X-Cache: HIT";      try_files $1.webp $1 =404;
    } 
  } 
}
				
			

Sử dụng CDN trong dự án WordPress với WP-Rocket

Vào phần CDN sau đó chọn vào phần Enable Content Delivery Network. Sau đó điền tên miền đã sử dụng để set up CDN ở bước trên vào sau đó chọn loại file để cache. Có thể chọn Images, CSS, JS & CSS hoặc là tất cả các file trên.

CDn-Rocket

Kiểm tra CDN đã hoạt động chưa.

Truy cập vào trang Web và bật DevTool bằng phim F12 và kiểm tra.

Đầu tiên mình sẽ dùng chính mạng nơi mình làm việc để kiểm tra.

CDN-HCM

Tại đây các file tĩnh của mình sẽ được load lại POP đặt gần mình nhất(trong cấu hình mình sẽ đặt tên POP này là HCM-CDN-01)

Sau đó kiểm tra với VPN kết nối qua Singapore và kiểm tra lại.

CDN-SGP

Có thể thấy lần này các file tĩnh mình đã được HIT ở POP CDN đặt tại Singapore của mình.

Kết luận:

– Có thể thấy rằng CDN là một phần quan trong giúp “gánh tải” cho web server của bản thân.
– Sử dụng CDN tự build có thể sẽ khó khăn về mặt kỹ thuật khi cần nhiều kiến thức mới có thể setup tuy nhiên sẽ được lợi khi tiết kiệm nhiều chi phí như băng thông, dung lượng……

Hy vọng qua bài viết này các bạn sẽ có thể hiểu được tầm quan trọng của CDN và có thể tự build một CDN đơn giản cho Webserver của mình nhé.

Ngoài ra các bạn có thể tham khảo một số bài viết khác chia sẽ kiến thức của mình trong quá trình làm việc tại đây.

Tài liệu tham khảo

CDN Review http://www.cdnreviews.com/

CDN – Content Delivery Network http://www.webopedia.com/TERM/C/CDN.html

7 Reasons to use a Content Delivery Networkhttp://www.sitepoint.com/7-reasons-to-use-a-cdn/

Speedy Web Content Delivery with CDNs http://windowsitpro.com/networking/speedy-web-content-delivery-cdns

By admin

Related Post

Leave a Reply

Your email address will not be published. Required fields are marked *

error: Content is protected !!
Don`t copy text!