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 process và và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 -ttrước khireload. Một lỗi gõ trong config production mà bạnreloadmù 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ảng | Config chính | Config 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ó
Hostheader làlocalhost. - khi request đường dẫn như
/index.html, tìm/var/www/lab/index.htmltrên đĩa. - nếu URL là một thư mục (
/), phục vụindex.htmltrong đó.
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 -t→nginx -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 đủ.
- 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. - Tìm đường dẫn: chạy
nginx -Vvà xác địnhnginx.confcùng thư mục includes. - Phục vụ trang của bạn: tạo một block
serverở cổng8081phục vụ một thư mục vớiindex.htmlcủa bạn. - Cố tình làm hỏng: xoá một dấu
;trong config, chạynginx -t, và đọc thông báo lỗi cùng số dòng chính xác. - Xem log:
tail -faccess 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. - Nâng cao: đổi
worker_processestrongnginx.confthành2, reload, và xác nhận bằngps aux | grep nginxrằng đúng hai worker đang chạy.