Bài này hoặc loạt bài này (nếu mình có thời gian) mình thực hiện bằng cách vừa học vừa viết lại, nguồn từ internet, chủ yếu mình lược dịch lại từ các trang web nước ngoài. Mục đích vừa để chia sẻ vừa để lại lưu trữ (sau này mình quên có thể vào để xem lại). Ok, dài dòng đủ rồi, vào bài thôi:
Xem thêm bài liên quan:
Hướng dẫn Nginx – Phần 2: Performance
Giới thiệu về nginx
Nếu bạn tìm tới bài viết này chắc cũng đã hiểu sơ qua về Nginx. Nginx ban đầu được tạo ra như một máy chủ web để giải quyết vấn đề C10k . Và như một máy chủ web (web server) , nó có thể phục vụ dữ liệu của bạn với tốc độ gần bằng ánh sáng. Nhưng Nginx không chỉ là một máy chủ web. Bạn có thể sử dụng nó như một reverse proxy, làm cho việc tích hợp dễ dàng với các máy chủ ngược dòng chậm hơn (slower upstream servers) (như Unicorn, hoặc Puma). Bạn có thể phân phối lưu lượng truy cập của bạn một cách hoàn hảo (load balancer: cân bằng tải), stream media, thay đổi kích thước ảnh khi đang di chuyển, cache nội dung, và nhiều thứ nữa.
Huong-dan-nginx-sofsog.com
Kiến trúc cơ bản của nginx bao gồm một quy trình tổng (Master process) và các công nhân (workers) của nó. Master process phải đọc file cấu hình và duy trì những “process worker”, trong khi các workers thực hiện xử lý các yêu cầu thực tế.
Các lệnh cơ bản
Để bắt đầu nginx, bạn chỉ cần gõ:
1 |
sudo nginx |
Trong lúc nginx đang chạy, bạn có thể quản lý nó bằng cách gửi các lệnh thích hợp:
1 |
sudo nginx -s signal_thich-hop |
Một số Signal có sẵn:
stop
: shutdown nhanh nginxquit
: shutdown một cách cẩn thận, duyên dáng (^_^) (Chờ đợi các workers hoàn thành các tiến trình của chúng rồi mới tắt)reload
: Tải lại file cấu hìnhreopen
: Mở lại các file nhật ký (file log)
Directive và Context (chỉ thị và bối cảnh, cái này tốt nhất là không dịch)
Theo mặc định, file cấu hình của nginx có thể được tìm thấy trong các đường dẫn sau:
/etc/nginx/nginx.conf
,/usr/local/etc/nginx/nginx.conf
, hoặc/usr/local/nginx/conf/nginx.conf
Trong file cấu hình này bao gồm:
- directive: tùy chọn chứa tên và thông số (name và parameters), phải được kết thúc bằng dấu chấm phẩy.
1 |
gzip on; |
- context: Đây là nơi để bạn có thể khai báo các directive (tương tự như phạm vi “scope” trong các ngôn ngữ lập trình)
1 2 3 4 5 6 7 8 9 |
worker_processes 2; # directive trong global context (chỉ thị trong ngữ cảnh chung) http { # http context (ngữ cảnh http) gzip on; # directive trong http context server { # server context (ngữ cảnh server) listen 80; # directive trong server context } } |
Các loại directive:
Bạn phải cẩn thận khi sử dụng một directive trong nhiều context, vì mô hình kế thừa (inheritance model) là khác nhau đối với các directive khác nhau. Có 3 loại directive, mỗi loại lại có mô hình kế thừa (inheritance model) riêng.
Normal:
1 2 3 4 5 6 7 8 9 10 11 12 |
gzip on; gzip off; # Không hợp lệ, vì chỉ có một directive trong cùng một context. server { location /downloads { gzip off; } location /assets { # gzip được bật ở đây } } |
Array:
Việc thêm nhiều directive trong cùng một context sẽ thêm vào các giá trị, thay vì ghi đè chúng hoàn toàn. Việc định nghĩa một directive trong một subcontext sẽ ghi đè tất cả các giá trị cha trong subcontext đã cho.
1 2 3 4 5 6 7 8 9 10 |
error_log /var/log/nginx/error.log; error_log /var/log/nginx/error_notive.log notice; error_log /var/log/nginx/error_debug.log debug; server { location /downloads { # Dòng dưới này sẽ ghi đè toàn bộ các directive đã cho bên trên error_log /var/log/nginx/error_downloads.log; } } |
Action directive (chỉ thị hành động)
Hành động (action) là loại directive thay đổi mọi thứ. Hành vi kế thưa chúng sẽ phụ thuộc vào mô-đun.
Ví dụ, trong trường hợp rewrite directive, mỗi directive phù hợp sẽ được thực hiện:
1 2 3 4 5 6 7 8 |
server { rewrite ^ /foobar; location /foobar { rewrite ^ /foo; rewrite ^ /bar; } } |
Nếu user nạp: /sample
:
- server rewrite được thực hiện , rewriting từ
/sample
, thành/foobar
- location
/foobar
khớp (subcontext) - location rewrite ở dòng đầu tiền sẽ được thực hiện, rewriting từ
/foobar
, thành/foo
- location rewrite ở dòng thứ hai được thực hiện tiếp sau đó, rewriting từ
/foo
, thành/bar
Một ví dụ khác với return directive:
1 2 3 4 5 6 |
server { location / { return 200; return 404; } } |
Trong trường hợp bên trên, trạng thái 404 được trả về ngay lập tức.
Processing requests
Bên Trong nginx, ban có thể chỉ định nhiều máy chủ ảo, mỗi máy chủ được mô tả bằng server { } context (ngữ cảnh server)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
server { listen *:80 default_server; server_name sofsog.com; return 200 "Hello from sofsog.com"; } server { listen *:80; server_name server2.com; return 200 "Hello from server2.com"; } server { listen *:81; server_name server3.com; return 200 "Hello from server3.com"; } |
- Danh sách server trên IP:port, với một
server_name
directive phù hợp (match) - Danh sách server trên IP:port, với
default_server
được đánh dấu - Danh sách server trên IP:port, đầu tiên được định nghĩa
- Nếu không có kết quả phù hợp, từ chối kết nối.
Trong kết ví dụ cấu hình bên trên, kết quả sẽ là:
1 2 3 4 5 |
Gửi yêu cầu đến: server2.com:80 => "Hello from server2.com" Gửi yêu cầu đến www.server2.com:80 => "Hello from sofsog.com" Gửi yêu cầu đến server3.com:80 => "Hello from sofsog.com" Gửi yêu cầu đến server2.com:81 => "Hello from server3.com" Gửi yêu cầu đến server3.com:81 => "Hello from server3.com" |
server_name
directive
server_name directive chấp nhận nhiều giá trị. Nó cũng xử lý các ký tự đại diện và biểu thức thông dụng. (wildcard và regular expressions)
1 2 3 4 |
server_name sofsog.com www.sofsog.com; # exact match server_name *.sofsog.com; # wildcard matching server_name sofsog.*; # wildcard matching server_name ~^[0-9]*\.sofsog\.com$; # regular expressions matching |
Khi có sự không rõ ràng, nginx sử dụng thứ tự sau:
- Tên chính xác
- Tên ký tự đại diện dài nhất bắt đầu bằng dấu sao, vd: “*.example.org”
- Tên ký tự đại diện dài nhất kết thúc bằng dấu sao, vd: “mail.*”
- Biểu thức thông dụng (regular expressions) khớp đầu tiên (Theo thứ tự xuất hiện trong file cấu hình)
Nginx sẽ lưu trữ 02 hash tables (bảng băm) là: tên chính xác, tên ký tự đại diện dài nhất bắt đầu bằng dấu sao, tên ký tự đại diện dài nhất kết thúc bằng dấu sao. Nếu kết quả không nằm trong bất kỳ bảng nào, các biểu thức thông đụng (regular expressions) sẽ được kiểm tra tuần tự.
1 |
server_name .sofsog.com; |
Là viết tắt của:
1 |
server_name sofsog.com www.sofsog.com *.sofsog.com; |
Nhưng giữa 2 cách viết trên vẫn có sự khác biệt là: .sofsog.com được lưu trữ trong bảng thứ hai, có nghĩa là nó chậm hơn một chút so với khai báo rõ ràng (sofsog.com www.sofsog.com *.sofsog.com)
listen
directive
Trong hầu hết các trường hợp, bạn sẽ thấy rằng listen
directive chấp nhận các giá trị IP:port
1 2 3 4 5 6 7 8 |
listen 127.0.0.1:80; listen 127.0.0.1; # Sẽ mặc định cổng 80 listen *:81; listen 81; # mặc định tất cả các IP (tên miền) được sử dụng listen [::]:80; # IPv6 addresses listen [::1]; # IPv6 addresses |
Tuy nhiên, bạn cũng có thể chỉ định UNIX-domain sockets
1 |
listen unix:/var/run/nginx.sock; |
Bạn thậm chí có thể sử dụng hostname
1 2 |
listen localhost:80; listen sofsog.com:80; |
Điều này nên được sử dụng thận trọng, vì tên máy chủ (hostname) có thể không được giải quyết khi khởi chạy nginx, khiến nginx không thể liên kết trên TCP socket đã cho.
Cấu hình cơ bản nginx
Với tất cả kiến thức bên trên, chúng ta có thể tạo và hiểu cấu hình tối thiểu cần thiết để chạy nginx
1 2 3 4 5 6 7 8 9 10 11 12 |
# /etc/nginx/nginx.conf events {} # Bối cảnh events cần được xác định để xem xét cấu hình hợp lệ http { server { listen 80; server_name sofsog.com www.sofsog.com *.sofsog.com; return 200 "Hello"; } } |
root
, location
, và try_files
directive
root
directive
root
directive khai báo thư mục gốc cho các yêu cầu, cho phép nginx ánh xạ yêu cầu gửi đến (incoming request) vào file hệ hống.
1 2 3 4 5 |
server { listen 80; server_name sofsog.com; root /var/www/sofsog.com; } |
Điều này cho phép nginx trả lại nội dung máy chủ theo yêu cầu
1 2 |
sofsog.com:80/index.html # returns /var/www/sofsog.com/index.html sofsog.com:80/foo/index.html # returns /var/www/sofsog.com/foo/index.html |
location
directive
location
directive đặt cấu hình tùy thuộc vào URI được yêu cầu.
location [modifier] path
1 2 3 |
location /foo { # ... } |
1 2 3 4 5 |
/foo /fooo /foo123 /foo/bar/index.html ... |
location
directives có thể được sử dụng trong một context nhất định.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
server { listen 80; server_name sofsog.com; root /var/www/sofsog.com; location / { return 200 "root"; } location /foo { return 200 "foo"; } } |
1 2 3 4 |
sofsog.com:80 / # => "root" sofsog.com:80 /foo # => "foo" sofsog.com:80 /foo123 # => "foo" sofsog.com:80 /bar # => "root" |
1 2 3 4 |
= - Exact match ^~ - Preferential match ~ && ~* - Regex match no modifier - Prefix match |
Nginx đầu tiên sẽ kiểm tra bất kỳ “exact match” nào. Nếu nó không tìm thấy, nó sẽ tìm kiếm những preferential. Nếu match này cũng thất bại, các regex match sẽ được kiểm tra theo thứ tự xuất hiện của chúng. Nếu mọi thứ không thành công, thì giá trị tiền tố cuối cùng (prefix match) sẽ được sử dụng.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
location /match { return 200 'Prefix match: matches everything that starting with /match'; } location ~* /match[0-9] { return 200 'Case insensitive regex match'; } location ~ /MATCH[0-9] { return 200 'Case sensitive regex match'; } location ^~ /match0 { return 200 'Preferential match'; } location = /match { return 200 'Exact match'; } |
1 2 3 4 5 |
/match # => 'Exact match' /match0 # => 'Preferential match' /match1 # => 'Case insensitive regex match' /MATCH1 # => 'Case sensitive regex match' /match-abc # => 'Prefix match: matches everything that starting with /match' |
try_files
directive
1 |
try_files $uri index.html =404; |
Ví dụ bên trên: đối với yêu cầu /foo.html, nó sẽ cố gắng trả về các file theo thứ tự sau:
- $uri ( /foo.html )
- index.html
- Nếu không tìm thấy: 404.
1 2 3 4 5 6 |
server { try_files $uri /index.html =404; location / { } } |
Do đó, bạn nên tránh try_files trong server context :
1 2 3 4 5 |
server { location / { try_files $uri /index.html =404; } } |
Kết luận
Cảm ơn các bạn đã đọc đến đây. Loạt bài này sẽ không thể có được nếu không có số lượng lớn tài nguyên được tìm thấy trên internet. Dưới đây là một số trang web tuyệt vời mà mình thấy đặc biệt hữu ích khi viết loạt bài này:
- nginx docs
- nginx blog
- nginx fundamentals on udemy
- Ilya Grigorik blog, và cuốn sánh của anh ta: High Performance Browser Networking
- Martin Fjordvald blog
Lược dịch từ: netguru.co