---
id: networking-osi-protocols
title: "Mô hình mạng và protocol"
track: networking
trackTitle: "Networking Fundamentals"
order: 1
level: core
status: published
estimatedMinutes: 45
prerequisites:
  - linux-shell-scripting
next: networking-cli-tools
reviewedAgainst: 2026-10-14
sources:
  - title: "RFC 9293 — Transmission Control Protocol"
    url: https://www.rfc-editor.org/rfc/rfc9293
  - title: "RFC 791 — Internet Protocol"
    url: https://www.rfc-editor.org/rfc/rfc791
  - title: "RFC 1035 — Domain names, implementation and specification"
    url: https://www.rfc-editor.org/rfc/rfc1035
  - title: "RFC 9110 — HTTP Semantics"
    url: https://www.rfc-editor.org/rfc/rfc9110
  - title: "RFC 8446 — The Transport Layer Security (TLS) Protocol Version 1.3"
    url: https://www.rfc-editor.org/rfc/rfc8446
---

# Mô hình mạng và protocol

## Để làm gì

Nhìn vào một kết nối web, bạn cần chỉ ra được nó đang ở bước DNS, IP, TCP, TLS hay HTTP, và gắn bước đó vào đúng tầng trên sơ đồ OSI. Khi có sự cố, khoanh đúng lớp trước rồi mới mở các lệnh debug ở bài sau, thì mới không mò kim đáy bể.

## Gồm những gì

- Mô hình OSI đủ bảy tầng, dùng làm khung để nhớ, không phải kiến trúc chạy thật.
- Thành phần hay được gắn vào từng tầng: cáp và Wi-Fi, MAC và switch, IP và TTL của gói, TCP hoặc UDP, rồi HTTP, DNS, SSH.
- Stack thật của Internet: IP, TCP hoặc UDP, TLS bọc payload khi scheme là `https`, rồi protocol của app.
- DNS và các record hay gặp.
- HTTP và chỗ của TLS.
- Số port do IANA đăng ký.

Bài này không cấu hình firewall, cũng không viết server. Bài thứ ba của chặng sẽ dùng lại các khái niệm này với Nginx.

## Dùng khi nào

Mỗi khi đọc một URL, bạn cần hình dung được máy sẽ tra domain, mở connection, handshake TLS, rồi mới gửi HTTP request.

Mô hình OSI đủ bảy lớp không phải là kiến trúc Internet đang chạy. Đừng đổ mọi sự cố cho "tầng 6" chỉ vì một sơ đồ cũ xếp TLS vào đó.

## Kiến thức cốt lõi

Một request tới `https://api.example.com/healthz` đi qua các bước sau:

1. DNS đổi tên `api.example.com` thành địa chỉ IP.
2. IP định tuyến packet tới máy đó.
3. TCP tạo phiên tin cậy tới một port.
4. TLS tạo kênh mã hóa trên phiên TCP đó khi scheme là `https`.
5. HTTP gửi method, path, và header bên trong kênh TLS.

Gắn các bước này vào OSI cho dễ nhớ. Tầng 7 ở trên cùng, sát ứng dụng. Tầng 1 ở dưới, sát dây và sóng. Ô nét đứt là chỗ sơ đồ có tên nhưng không có protocol riêng để bạn cấu hình.

<div class="osi">
<div class="osi-row" style="--layer:#dbeafe"><div class="osi-num">7<small>Application</small></div><div class="osi-body"><div class="osi-name">Ứng dụng</div><div class="osi-bits"><span class="osi-bit">HTTP</span><span class="osi-bit">DNS</span><span class="osi-bit">SSH</span></div><p class="osi-note">Method, path, header, status. DNS đổi tên thành IP. SSH mở shell, thường port 22.</p></div></div>
<div class="osi-row" style="--layer:#e0e7ff"><div class="osi-num">6<small>Presentation</small></div><div class="osi-body"><div class="osi-name">Trình diễn</div><div class="osi-bits"><span class="osi-bit">TLS</span><span class="osi-bit">SSL là tên cũ</span></div><p class="osi-note">Trên stack đang chạy, TLS là kênh bọc HTTP sau khi TCP đã nối, không phải một tầng để sửa riêng.</p></div></div>
<div class="osi-row is-memo" style="--layer:#f3f4f6"><div class="osi-num">5<small>Session</small></div><div class="osi-body"><div class="osi-name">Phiên</div><div class="osi-bits"><span class="osi-bit">cookie của app</span><span class="osi-bit">phiên TLS</span></div><p class="osi-note">Sơ đồ ghi "quản lý phiên". Không có protocol tầng 5 để bật khi user mất đăng nhập.</p></div></div>
<div class="osi-row" style="--layer:#dcfce7"><div class="osi-num">4<small>Transport</small></div><div class="osi-body"><div class="osi-name">Giao vận</div><div class="osi-bits"><span class="osi-bit">TCP</span><span class="osi-bit">UDP</span><span class="osi-bit">port</span></div><p class="osi-note">TCP bắt tay ba bước rồi giữ byte stream. UDP gửi datagram, không tự truyền lại.</p></div></div>
<div class="osi-row" style="--layer:#fef3c7"><div class="osi-num">3<small>Network</small></div><div class="osi-body"><div class="osi-name">Mạng</div><div class="osi-bits"><span class="osi-bit">IP</span><span class="osi-bit">router</span><span class="osi-bit">TTL của gói</span></div><p class="osi-note">TTL giảm mỗi hop. Về 0 thì router hủy gói, để khỏi kẹt routing loop.</p></div></div>
<div class="osi-row" style="--layer:#ffedd5"><div class="osi-num">2<small>Data link</small></div><div class="osi-body"><div class="osi-name">Liên kết dữ liệu</div><div class="osi-bits"><span class="osi-bit">MAC</span><span class="osi-bit">switch</span></div><p class="osi-note">Frame chỉ đi trong một LAN. Switch chuyển theo địa chỉ MAC.</p></div></div>
<div class="osi-row" style="--layer:#e7e5e4"><div class="osi-num">1<small>Physical</small></div><div class="osi-body"><div class="osi-name">Vật lý</div><div class="osi-bits"><span class="osi-bit">cáp</span><span class="osi-bit">tín hiệu</span><span class="osi-bit">Wi-Fi</span></div><p class="osi-note">Bit trên dây hoặc trên sóng. Chưa có địa chỉ IP ở tầng này.</p></div></div>
</div>

Cùng một byte của `GET /healthz`, nhìn từ ngoài vào trong. Lớp ngoài là thứ đi trên dây. Lớp trong cùng là thứ app đọc:

<div class="pkt"><div class="w-bit">Tín hiệu trên cáp hoặc Wi-Fi<div class="w-frame">Frame MAC, switch chuyển trong một LAN<div class="w-ip">IP, địa chỉ nguồn và đích, TTL giảm mỗi router<div class="w-tcp">TCP, port 443, SYN rồi SYN-ACK rồi ACK<div class="w-tls">TLS bọc payload. SSL là tên cũ<div class="w-http">HTTP: method, path, header, status 200 hoặc 500</div></div></div></div></div></div></div>

**HTTP** nằm ở tầng ứng dụng. Client gửi method (`GET`, `POST`), path (`/healthz`) và header. Server trả status (`200`, `500`). DNS và SSH cũng là protocol tầng này, nhưng không phải HTTP: DNS đổi tên thành IP, SSH mở shell từ xa, thường trên port 22. Bài HTTP nói method và status. Bài SSH nằm ở chặng Linux.

**TLS** mã hóa payload của tầng ứng dụng để người đứng giữa đường truyền không đọc được. Nó chạy sau khi TCP đã nối: TCP xong, TLS handshake tạo khóa, rồi HTTP mới đi bên trong. SSL là tên cũ, bản còn gặp trong tài liệu lỗi thời. Chỗ bạn cấu hình hôm nay là TLS. Sơ đồ lớp hay vẽ TLS ở tầng trình diễn để có ô bỏ vào. Đừng vì ô đó mà gọi mọi sự cố certificate là "hỏng tầng 6" rồi dừng. Certificate, tên trên SAN và chain nằm ở bài TLS.

**Tầng phiên** trên sơ đồ OSI là ô "duy trì và kết thúc phiên". Trên web không có một protocol tầng 5 để bạn bật lên. Phiên đăng nhập là cookie do app đặt. Phiên TLS là state của kênh mã hóa. Mất đăng nhập thì xem cookie và app, không xem một service tên session ở tầng 5.

**TCP** (spec hiện tại là RFC 9293) truyền một byte stream có thứ tự, có phát hiện mất gói và truyền lại. Nó mở phiên bằng bắt tay ba bước tới một port trên IP đích:

<div class="shake">
<div class="shake-who">Client</div>
<div class="shake-who">Server</div>
<p class="shake-msg to-right"><span>SYN</span><span class="shake-bar"></span><i>xin mở phiên</i></p>
<p class="shake-msg to-left"><span>SYN-ACK</span><span class="shake-bar"></span><i>đồng ý, xin chiều ngược lại</i></p>
<p class="shake-msg to-right"><span>ACK</span><span class="shake-bar"></span><i>xác nhận</i></p>
<p class="shake-after">Phiên TCP đã mở. Tới lượt TLS, rồi HTTP mới được gửi.</p>
</div>

Chưa có SYN-ACK thì chưa có phiên, HTTP chưa được gửi. UDP không bắt tay: nó gửi datagram và không tự truyền lại. HTTP/1.1 và HTTP/2 chạy trên TCP. HTTP/3 chạy trên QUIC, và QUIC dùng UDP. Vì vậy "web thì luôn là TCP port 443" không còn đúng với mọi connection hiện nay.

**IP và TTL của gói** nằm ở tầng mạng. Router chuyển packet giữa các mạng. Trong header IPv4, trường TTL là số hop còn được đi qua (RFC 791). Mỗi router giảm số đó ít nhất một. Về 0, router hủy gói và thường gửi ICMP Time Exceeded về nguồn, để một routing loop không giữ gói chạy vòng mãi. IPv6 dùng trường Hop Limit cho cùng việc đó. `traceroute` tăng dần giới hạn hop và nhìn chỗ gói chết để vẽ các router trên đường.

TTL này không phải TTL của bản ghi DNS. TTL của DNS là số giây một resolver được cache câu trả lời, nói ở bài DNS. Hạ TTL của bản ghi không chữa một gói đang chết vì hết hop. Tăng TTL của gói IP cũng không làm client thấy IP mới sớm hơn.

Spec DNS là RFC 1034 và RFC 1035. Một số record cần phân biệt:

| Record | Trỏ tới |
| --- | --- |
| `A` | Địa chỉ IPv4 |
| `AAAA` | Địa chỉ IPv6 |
| `CNAME` | Một tên miền khác |
| `NS` | Name server có thẩm quyền |
| `MX` | Máy nhận thư |
| `TXT` | Chuỗi văn bản, thường dùng cho kiểm tra quyền sở hữu và chính sách thư |

Resolver trên máy bạn hỏi một recursive resolver, và recursive resolver lần lượt hỏi tới authoritative server. Câu trả lời đi kèm TTL, nên khi bạn vừa đổi IP, không phải máy nào cũng thấy IP mới ngay.

RFC 9110 (HTTP Semantics) định nghĩa ý nghĩa của method và status, tách riêng khỏi cách đóng gói dữ liệu trên đường truyền. Các nhóm status bạn cần đọc được:

| Nhóm | Ý nghĩa vận hành |
| --- | --- |
| `2xx` | Máy đích đã xử lý thành công |
| `3xx` | Cần đi tiếp theo `Location` |
| `4xx` | Request sai hoặc không được phép |
| `5xx` | Máy đích gặp lỗi khi xử lý |

Port `80` và `443` là port IANA gán cho HTTP và HTTPS. App Node vẫn có thể nghe `3000` trên loopback, còn reverse proxy nghe `443` rồi chuyển tiếp vào `3000`.

TLS 1.3 được đặc tả trong RFC 8446. TLS ngăn người khác đọc hoặc sửa nội dung HTTP trên đường truyền, nhưng không vá được bug phân quyền bên trong app.

## Lệnh và code mẫu

Đường đi của một URL. Ở bài sau, bạn kiểm tra từng ô bằng lệnh:

<div class="net-flow">
<div class="net-step" style="--layer:#dbeafe"><b>DNS</b><span>api.example.com thành A hoặc AAAA</span></div>
<span class="net-arrow" aria-hidden="true">→</span>
<div class="net-step" style="--layer:#fef3c7"><b>IP</b><span>router đưa packet tới máy đích</span></div>
<span class="net-arrow" aria-hidden="true">→</span>
<div class="net-step" style="--layer:#dcfce7"><b>TCP</b><span>bắt tay tới port 443</span></div>
<span class="net-arrow" aria-hidden="true">→</span>
<div class="net-step" style="--layer:#e0e7ff"><b>TLS</b><span>kênh mã hóa trên phiên đó</span></div>
<span class="net-arrow" aria-hidden="true">→</span>
<div class="net-step" style="--layer:#dbeafe"><b>HTTP</b><span>GET /healthz</span></div>
</div>

App nghe trên port riêng. Proxy đón connection từ bên ngoài:

<div class="net-flow">
<div class="net-step"><b>Client</b><span>mở URL</span></div>
<span class="net-arrow" aria-hidden="true">→</span>
<div class="net-step" style="--layer:#e0e7ff"><b>Nginx</b><span>port 443, TLS</span></div>
<span class="net-arrow" aria-hidden="true">→</span>
<div class="net-step" style="--layer:#dbeafe"><b>Node</b><span>port 3000, HTTP</span></div>
</div>

## Thực hành

Lấy một URL của app bạn đang làm và viết ra năm dòng: domain, record DNS cần có, port public, process nhận connection public, và protocol ứng dụng. Giữ bản này để đối chiếu với `dig`, `ss` và `curl` ở bài tiếp theo.

Với `https://example.com`, bản mẫu trông như sau:

```text
ten mien: example.com
record: A và AAAA
cong cong khai: 443
process cong khai: web server cua example.com
protocol ung dung: HTTP ben trong TLS
```

## Kết quả mong đợi

Có năm dòng đó, bạn chọn được lệnh debug phù hợp: lỗi domain thì bắt đầu từ DNS, connection refused thì xem process và port, lỗi certificate thì xem TLS, còn lỗi `4xx` hoặc `5xx` thì xem HTTP và app.

## Checklist

- [ ] Tách DNS, TCP, TLS, và HTTP thành bốn bước khác nhau.
- [ ] Chỉ một triệu chứng vào đúng tầng: status HTTP, bắt tay TCP, hay gói IP hết hop.
- [ ] Phân biệt TTL của gói IP với TTL của bản ghi DNS.
- [ ] Phân biệt record `A`, `AAAA`, và `CNAME`.
- [ ] Giải thích vì sao app nghe port `3000` trong khi user mở port `443`.
- [ ] Nhớ HTTP/3 không dùng TCP.

## Thẻ ôn

### networking-osi-protocols-steps
kind: distinguish
cue: Một URL không mở thì tách từng bước: DNS đổi tên thành IP, TCP mở phiên, TLS nếu là https, rồi mới tới HTTP. Timeout TCP, NXDOMAIN và HTTP 500 là ba chuyện khác nhau.

Q: Người dùng không mở được `https://api.example.com/healthz`. Trước khi kết luận "app chết", request phải đi qua những bước nào, và vì sao timeout TCP, `NXDOMAIN`, HTTP `500` không phải cùng một lỗi?

A: DNS đổi tên `api.example.com` thành một địa chỉ IP. Chưa có IP thì chưa có gì để nối. TCP mở một phiên tới một port trên IP đó. Phiên không lập được thì chưa tới lượt ứng dụng. Scheme `https` thì TLS tạo kênh mã hóa trên phiên TCP đó. HTTP mới gửi method, path `/healthz` và header bên trong kênh. Timeout TCP là không bắt tay được tới port. `NXDOMAIN` là DNS nói tên không tồn tại. HTTP `500` là đã vào được app và app trả lỗi. Ba triệu chứng, ba chỗ sửa.

### networking-osi-protocols-records
kind: distinguish
cue: Bản ghi `A` là IPv4, `AAAA` là IPv6, `CNAME` trỏ sang một tên khác và resolver phải hỏi tiếp. Đừng để `CNAME` đứng cùng `A` trên một tên.

Q: Một tên miền cần trả lời cho client IPv4, client IPv6, và có lúc cần trỏ cả tên sang một tên khác. Bản ghi `A`, `AAAA` và `CNAME` mỗi loại trả gì? Vì sao không gắn `CNAME` và `A` cùng lúc cho một tên?

A: `A` trả một địa chỉ IPv4. `AAAA` trả một địa chỉ IPv6. Client hỏi loại nào được loại đó, không tự hiểu địa chỉ kia thay được. `CNAME` không trả IP. Nó nói tên này là biệt danh của một tên khác, và resolver phải hỏi tiếp tên đích rồi mới ra IP. Một tên đã là `CNAME` thì không được có bản ghi loại khác cùng hiệu lực, kể cả `A`. Muốn vừa có IP vừa có biệt danh thì tách tên, đừng chồng hai loại lên một nhãn.

### networking-osi-protocols-ports
kind: decide
cue: User mở 443 trên reverse proxy. App nghe 3000 ở phía sau. Hai port không phải một chỗ, và 3000 không cần mở ra Internet khi Nginx đã là điểm vào.

Q: Ứng dụng lắng nghe port 3000. Người dùng lại mở `https://...` tức port 443. Có người muốn mở luôn security group cho 3000 ra Internet cho "trùng port app". Hai port có phải một chỗ không, và khi đã có Nginx thì 3000 nên để đâu?

A: Không phải một chỗ. Người dùng tới port 443 trên reverse proxy, nơi TLS thường được kết thúc. Proxy mở một kết nối riêng tới app ở port 3000, thường là loopback hoặc mạng nội bộ. App không cần biết user đang dùng 443. Port 3000 không cần nằm trên Internet khi Nginx đã là điểm vào duy nhất. Mở 3000 ra ngoài là thêm một cửa không đi qua proxy, không đi qua rule bạn đã đặt ở Nginx.

### networking-osi-protocols-http3
kind: default
cue: HTTP/1.1 và HTTP/2 chạy trên TCP. HTTP/3 chạy trên QUIC, và QUIC dùng UDP, không phải TCP port 443 theo nghĩa cũ.

Q: Bạn đang bắt gói và giả định mọi website đều là TCP tới port 443. Giả định đó còn đúng khi site dùng HTTP/3 không?

A: Không còn đúng cho mọi site. HTTP/1.1 và HTTP/2 chạy trên TCP, thường là port 443 khi có TLS. HTTP/3 chạy trên QUIC, và QUIC dùng UDP. Một bộ lọc chỉ cho TCP 443 đi qua sẽ không thấy, hoặc sẽ chặn, traffic HTTP/3. Trước khi kết luận "không có kết nối" từ một bản bắt chỉ có TCP, hỏi site có đang dùng HTTP/3 không.

### networking-osi-protocols-map
kind: distinguish
cue: HTTP status nằm ở tầng ứng dụng. Bắt tay TCP nằm ở tầng giao vận. Gói hết hop nằm ở tầng mạng. TLS bọc HTTP sau khi TCP đã nối, đừng gom mọi sự cố vào "tầng 6".

Q: Một URL `https` không mở. Người trực nói "hỏng tầng 6" vì sơ đồ cũ ghi TLS ở tầng trình diễn. `500`, bắt tay TCP không có SYN-ACK, và gói IP bị hủy giữa đường, mỗi cái ngồi ở tầng nào? DNS và SSH có phải HTTP không?

A: `500` là HTTP, tầng ứng dụng: request đã vào app và app trả lỗi. Không có SYN-ACK là TCP, tầng giao vận, phiên tới port chưa mở. Gói bị hủy vì hết hop là IP, tầng mạng: TTL hoặc Hop Limit về 0 thì router bỏ gói để khỏi kẹt routing loop. TLS mã hóa payload HTTP sau khi TCP đã nối. Ô tầng trình diễn trên sơ đồ chỉ là chỗ để nhớ việc mã hóa, không phải một tầng bạn sửa riêng. DNS và SSH cũng là protocol tầng ứng dụng, nhưng mỗi cái một việc: DNS đổi tên thành IP, SSH mở shell, không đi chung đường với method và status của HTTP.

### networking-osi-protocols-ipttl
kind: distinguish
cue: TTL trong header IP đếm số router còn được đi qua, về 0 thì gói bị hủy. TTL của bản ghi DNS là số giây được cache. Hai số không chữa cho nhau.

Q: Log nói gói chết vì TTL về 0. Đồng nghiệp bảo hạ TTL của bản ghi DNS xuống 60 giây để user hết cache và đi đường mới. Hai TTL có phải một thứ không, và hạ bản ghi DNS có cứu gói đang bị hủy không?

A: Không phải một thứ, và không cứu được. Trong header IPv4, TTL là số hop còn lại. Mỗi router giảm ít nhất một. Về 0, router hủy gói và thường gửi ICMP Time Exceeded, để một routing loop không giữ gói chạy mãi. IPv6 làm cùng việc bằng Hop Limit. `traceroute` dựa vào chỗ gói chết để vẽ các router. TTL trên bản ghi DNS là số giây resolver được giữ câu trả lời cũ. Hạ số giây đó không đổi đường đi của gói, và tăng TTL của gói cũng không làm client thấy IP mới sớm hơn.

## Lỗi thường gặp

**Gọi mọi sự cố là "lỗi mạng", hoặc là "tầng 6".** Timeout ở TCP, `NXDOMAIN` ở DNS và HTTP `500` là ba chuyện khác nhau. Sơ đồ cũ ghi TLS ở tầng trình diễn không biến mọi sự cố thành một tầng để sửa.

**Nhầm TTL của gói IP với TTL của bản ghi DNS.** Một số đếm hop và về 0 thì router hủy gói. Số kia là giây cache. Hạ TTL của zone không chữa routing loop.

**Thấy không có SYN-ACK mà vẫn đi đọc log của app.** Bắt tay TCP chưa xong thì HTTP chưa được gửi. Xem port và đường tới máy đích trước.

**Đặt cả `CNAME` và `A` cho cùng một tên mà không rõ record nào đang có hiệu lực.** Khi một tên đã có `CNAME`, resolver sẽ tra tiếp sang tên đích. Đừng để hai kiểu trả lời đụng nhau trên cùng một tên; hãy sửa ở nhà cung cấp DNS theo đúng record đang có hiệu lực.

**Mở port của app ra Internet vì chưa kịp cấu hình reverse proxy.** Khi Nginx đã là điểm vào, port `3000` chỉ nên nằm trong mạng nội bộ hoặc trên loopback.

## Nguồn

1. [RFC 9293](https://www.rfc-editor.org/rfc/rfc9293) — TCP, bắt tay và byte stream.
2. [RFC 791](https://www.rfc-editor.org/rfc/rfc791) — trường TTL của IPv4, giảm theo từng hop.
3. [RFC 1034](https://www.rfc-editor.org/rfc/rfc1034) và [RFC 1035](https://www.rfc-editor.org/rfc/rfc1035) — mô hình và cách cài DNS.
4. [RFC 9110](https://www.rfc-editor.org/rfc/rfc9110) — semantics của HTTP.
5. [RFC 9114](https://www.rfc-editor.org/rfc/rfc9114) — HTTP/3.
6. [RFC 8446](https://www.rfc-editor.org/rfc/rfc8446) — TLS 1.3.
7. [IANA Service Name and Port Number Registry](https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml) — port đã đăng ký.

## Tiếp theo

[Công cụ chẩn đoán mạng](./02-cli-tools.md)
