jvinhit//lab

Search posts

Type to search across journal entries.

navigate open esc close

Nginx from Zero to Production · Part 1 — Fundamentals & Local Install

Start Nginx from zero: what it really is (web server, reverse proxy, load balancer), the master/worker event-driven model, install it locally on macOS/Linux/Docker, and serve your first static site — with exercises.

Đây là Phần 1 của series 5 bài đưa bạn từ “mới thấy nginx trong tutorial” đến tự tin cấu hình, proxy, bảo mật và debug Nginx trên production. Mỗi phần đều thực hành và kết thúc bằng bài tập — cài đặt, làm hỏng, rồi sửa.

Nginx (đọc là “engine-x”) chạy phía sau một phần lớn của web: nó đứng trước ứng dụng của bạn và quyết định phục vụ cái gì, như thế nào, và cho ai. Hết Phần 1, bạn sẽ có nó chạy trên máy mình, phục vụ một trang thật.


1. Nginx thực ra là gì?

Người ta gọi Nginx là “web server”, nhưng nói vậy là chưa đủ. Nó là một binary đóng bốn vai trò:

  • Web server tĩnh — phục vụ HTML, CSS, JS, ảnh thẳng từ đĩa, rất nhanh.
  • Reverse proxy — nhận request rồi chuyển tiếp tới ứng dụng backend (Node, Python, Go…), sau đó chuyển response về.
  • Load balancer — chia tải qua nhiều instance backend.
  • Đầu cuối TLS / cache / người gác cổng — xử lý HTTPS, cache response, giới hạn tốc độ kẻ lạm dụng.
                 ┌──────────────────────── NGINX ────────────────────────┐
   Internet ───► │  TLS termination · routing · cache · rate-limit        │
                 │        │                    │                          │
                 │        ▼                    ▼                          │
                 │  serve /static         proxy_pass to app(s)            │
                 └────────┼────────────────────┼─────────────────────────┘
                          ▼                     ▼
                    files on disk        ┌─── app :3000 ───┐
                    (html, css, js)      │  app :3001       │  (upstream pool)
                                         └─── app :3002 ───┘

Mô hình tư duy cho cả series: Nginx là cửa trước của hệ thống. Mọi thứ chạm tới app của bạn đều đi qua nó trước.

Tại sao nó nhanh đến vậy?

Các server cũ (như Apache prefork cổ điển) tạo một thread hoặc process cho mỗi kết nối. 10,000 10.000 kết nối → 10.000 thread → tốn bộ nhớ và chi phí chuyển ngữ cảnh khổng lồ. Đây là bài toán C10k kinh điển.

Nginx dùng mô hình hướng sự kiện, bất đồng bộ thay thế: một số ít worker process cố định, mỗi cái xử lý hàng nghìn kết nối trong một thread duy nhất qua event loop (epoll trên Linux, kqueue trên BSD/macOS). Không có chuyện một thread mỗi kết nối, nên bộ nhớ giữ ổn định khi traffic tăng.


2. Kiến trúc master / worker

Khi Nginx khởi động, bạn có một master processvài worker process:

   master process            (runs as root: reads config, binds :80/:443)
      │  forks
      ├── worker process #1   (runs as unprivileged user: handles requests)
      ├── worker process #2
      ├── worker process #3
      └── worker process #4   (usually one per CPU core)

Phân chia công việc:

  • Master đọc và kiểm tra config, gắn vào cổng đặc quyền (80/443), và quản lý worker — nhưng nó không xử lý request.
  • Mỗi worker xử lý kết nối client thật. Chúng chạy dưới user ít quyền (vd www-data, nginx) để an toàn.

Sự phân chia này là lý do Nginx có thể reload config mà không downtime: master khởi động worker mới với config mới, để worker cũ xử lý nốt request đang dang dở, rồi cho nghỉ. Ta sẽ dùng điều này liên tục:

nginx -t            # test config syntax BEFORE applying (do this every time)
nginx -s reload     # graceful reload: no dropped connections

Quy tắc cho cả series: luôn nginx -t trước khi reload. Một lỗi gõ trong config production mà bạn reload mù quáng có thể làm sập site.


3. Cài Nginx trên máy

Chọn cách phù hợp với máy bạn. Tôi khuyên cài trực tiếp (native) cho Phần 1–4 (phản hồi nhanh) và ta sẽ làm Docker đàng hoàng ở Phần 5.

macOS (Homebrew)

brew install nginx
brew services start nginx     # start now + on login
# Homebrew nginx listens on :8080 by default (no sudo needed)
curl -I http://localhost:8080

Linux (Debian/Ubuntu)

sudo apt update && sudo apt install -y nginx
sudo systemctl enable --now nginx   # start + enable on boot
curl -I http://localhost              # listens on :80

Mọi OS (Docker)

docker run --name nginx-lab -d -p 8080:80 nginx
curl -I http://localhost:8080

Dù cách nào, một response thành công trông như sau:

HTTP/1.1 200 OK
Server: nginx/1.27.0
Content-Type: text/html

Nếu thấy Server: nginx, bạn đã chạy được. Nếu curl báo connection refused, Nginx chưa chạy hoặc bạn dùng sai cổng.


4. File nằm ở đâu?

Điều này làm rối mọi người mới vì nó khác nhau theo nền tảng. Tìm đường dẫn thật bằng một lệnh:

nginx -V 2>&1 | tr ' ' '\n' | grep -E 'conf-path|prefix'

Vị trí thường gặp:

Nền tảngConfig chínhConfig site
Ubuntu/Debian/etc/nginx/nginx.conf/etc/nginx/sites-available/* + conf.d/*.conf
macOS (Homebrew, Apple)/opt/homebrew/etc/nginx/nginx.conf/opt/homebrew/etc/nginx/servers/*
macOS (Homebrew, Intel)/usr/local/etc/nginx/nginx.conf/usr/local/etc/nginx/servers/*
Docker (nginx image)/etc/nginx/nginx.conf/etc/nginx/conf.d/*.conf

Ý chính: nginx.conf chính thường kết thúc bằng dòng include để kéo vào tất cả file config từng-site của bạn. Bạn hiếm khi sửa chính nginx.conf — bạn thả một file vào thư mục được include.

# Near the bottom of nginx.conf — this is what loads your files:
http {
    # ...
    include /etc/nginx/conf.d/*.conf;        # Docker / RHEL style
    include /etc/nginx/sites-enabled/*;      # Debian/Ubuntu style
}

5. Phục vụ site tĩnh đầu tiên

Hãy phục vụ trang của riêng ta thay vì màn hình chào mặc định.

Bước 1 — tạo thư mục site và một file HTML:

sudo mkdir -p /var/www/lab
echo '<h1>Hello from Nginx</h1>' | sudo tee /var/www/lab/index.html

Bước 2 — viết một server block. Tạo một file trong thư mục includes (vd /etc/nginx/conf.d/lab.conf):

# /etc/nginx/conf.d/lab.conf
server {
    listen 8081;              # the port this site answers on
    server_name localhost;    # which hostname this block handles

    root /var/www/lab;        # base folder for files
    index index.html;         # default file when a directory is requested
}

Bước 3 — test và reload:

sudo nginx -t          # "syntax is ok" + "test is successful"
sudo nginx -s reload
curl http://localhost:8081     # → <h1>Hello from Nginx</h1>

Mỗi directive đã làm gì:

  • nhận kết nối ở cổng 8081.
  • xử lý request có Host header là localhost.
  • khi request đường dẫn như /index.html, tìm /var/www/lab/index.html trên đĩa.
  • nếu URL là một thư mục (/), phục vụ index.html trong đó.

Bạn vừa cấu hình Nginx trọn vẹn. Mọi thứ trong series này đều xây trên block server { ... } này.


6. Đọc xem chuyện gì đã xảy ra — log

Nginx ghi hai log mà bạn sẽ sống cùng: access log (mọi request) và error log (sự cố). Theo dõi chúng trong khi curl:

# paths vary; check `nginx -V` output or these common ones
sudo tail -f /var/log/nginx/access.log    # one line per request
sudo tail -f /var/log/nginx/error.log     # config + runtime errors

Một dòng access tiêu biểu cho biết method, path, status và kích thước:

127.0.0.1 - - [05/May/2026:10:00:00 +0000] "GET / HTTP/1.1" 200 31 "-" "curl/8.4.0"
                                            └ request ─────┘ └sts┘└sz┘        └ user-agent ┘

Khi có gì hỏng ở các phần sau, việc đầu tiên là tail -f error log — nó gần như luôn nói chính xác cái gì sai.


7. Tóm tắt

  • Nginx là cửa trước: server tĩnh, reverse proxy, load balancer, TLS/cache/gác cổng — một binary.
  • Nó nhanh nhờ mô hình worker hướng sự kiện, không phải một-thread-mỗi-kết-nối.
  • master quản lý config + worker; worker phục vụ request.
  • Quy trình bạn sẽ lặp lại mãi: sửa config → nginx -tnginx -s reload → xem log.

Tiếp theo — Phần 2: mô hình cấu hình: contexts, khớp location, try_files, virtual host — ngữ pháp đằng sau mọi config bạn sẽ viết.


Bài tập

Làm trên máy của bạn — đọc thôi không đủ.

  1. Cài & kiểm tra: cài Nginx theo cách của nền tảng bạn và xác nhận trang chào bằng curl -I.
  2. Tìm đường dẫn: chạy nginx -V và xác định nginx.conf cùng thư mục includes.
  3. Phục vụ trang của bạn: tạo một block server ở cổng 8081 phục vụ một thư mục với index.html của bạn.
  4. Cố tình làm hỏng: xoá một dấu ; trong config, chạy nginx -t, và đọc thông báo lỗi cùng số dòng chính xác.
  5. Xem log: tail -f access log, truy cập trang 3 lần, và xác định status code cùng kích thước byte của mỗi request.
  6. Nâng cao: đổi worker_processes trong nginx.conf thành 2, reload, và xác nhận bằng ps aux | grep nginx rằng đúng hai worker đang chạy.