Kioskgaming · Hạ tầng · Bản vẽ tham chiếu

Sơ đồ hệ thống & cấu hình Nginx

Cloudflare → nginx-lb (V1) → 5 server nội bộ — bản vẽ tham chiếu hiện trạng production. Kết luận chính và điểm cần xử lý: mục 03. Chi tiết từng tầng: Deep Dive hạ tầng.

Nguồn
repo nginx/ + Hetzner Console
Cập nhật
2026-07-04
Phạm vi
5 server Hetzner (Ashburn)
Bản đồ đầy đủ
ban-do-he-thong.md
luồng traffic production ! điểm cần xử lý — xem mục 03

01 Luồng request & vị trí gateway

Người dùng / Client app
HTTPS :443 → *.kioskservice.club
Cloudflare — DNS · CDN · SSL Flexible
TLS kết thúc tại Cloudflare · gắn CF-Connecting-IP / CF-Ray / X-Forwarded-Proto

HTTP :80 origin-pull — xem card "Realip / Cloudflare trust" bên dưới

nginx-lb (nginx:alpine) — gateway duy nhất toàn hệ (SPOF)
Chạy trên V1-Kiosk · network_mode: host · định tuyến theo server_name
V1 · gateway+app
10.0.0.5
  • nginx-lb :80 ★
  • API prod :3001–3004
  • API dev :4001
  • Dozzle :8080
V2 · app
10.0.0.4
  • API prod :3001–3004
  • API dev :4001
  • Dozzle :8080
V3 · data master
10.0.0.2
  • Redis master :6379
  • Postgres master :5432
  • Dozzle :8080
V4 · tools+replica
10.0.0.3
  • Redis/PG slave, RabbitMQ, Redis dev
  • RedisInsight, OmniDB, Dozzle
V5 · gamify+log
10.0.0.6
  • Gamify pro/dev, OpenSearch
  • Dashboards, Fluent Bit
!

Lưu ý vận hành: V2 và V3 dùng chung hostname mặc định ubuntu-8gb-ash-1 (Hetzner đặt theo spec, không phải tên định danh duy nhất). Không dùng hostname để nhận diện server khi SSH — chỉ IP mới chắc chắn: V2 = 10.0.0.4 / 178.156.166.189, V3 = 10.0.0.2 / 178.156.211.239.

02 Cấu hình Nginx minh hoạ theo từng chặng

① Cloudflare trust — realip

default.conf:28–43 (lặp lại mọi file conf)
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
… (15 dải CIDR của Cloudflare) …
set_real_ip_from 131.0.72.0/22;
real_ip_header CF-Connecting-IP;
Khôi phục IP thật của client vì mọi request tới origin đều đến từ IP Cloudflare.

② Forward scheme gốc

default.conf:46–54
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
proxy_set_header CF-Connecting-IP $http_cf_connecting_ip;
proxy_set_header CF-Ray $http_cf_ray;
SSL Flexible mode: origin chỉ nhận HTTP, nên backend phải đọc header này để biết phiên gốc là HTTPS.

③ Upstream API production

default.conf:1–16
upstream backend {
    least_conn;
    server 10.0.0.5:3001 weight=1 max_fails=3 fail_timeout=30s;
    server 10.0.0.5:3002 weight=1 max_fails=3 fail_timeout=30s;
    server 10.0.0.5:3003 weight=1 max_fails=3 fail_timeout=30s;
    server 10.0.0.5:3004 weight=1 max_fails=3 fail_timeout=30s;
    server 10.0.0.4:3001 weight=1 max_fails=3 fail_timeout=30s;
    server 10.0.0.4:3002 weight=1 max_fails=3 fail_timeout=30s;
    server 10.0.0.4:3003 weight=1 max_fails=3 fail_timeout=30s;
    server 10.0.0.4:3004 weight=1 max_fails=3 fail_timeout=30s;
}
8 instance: 4 trên V1 + 4 trên V2. Passive health check: down sau 3 lỗi / 30s.

④ WebSocket (Dozzle / RedisInsight / Dashboards)

dozzle.conf, redisinsight.conf, app-logs.conf
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_buffering off;
3 service này stream dữ liệu realtime qua WS — thiếu 3 dòng này thì UI đứng im dù nginx vẫn 200 OK.

⑤ Core nginx.conf

nginx/nginx.conf:1–37
worker_processes auto;
worker_connections 1024;
keepalive_timeout 65;
gzip on;
gzip_comp_level 6;
include conf.d/*.conf;
Trần kết nối đồng thời ≈ số core × 1024. V1 (CCX23) = 4 core → ~4096; V2/V4 (CCX13) = 2 core → ~2048.

⑥ Container nginx-lb

nginx.yml:1–15
image: nginx:alpine
container_name: nginx-lb
restart: always
network_mode: host
volumes:
  - ./nginx/conf.d:/etc/nginx/conf.d:ro
network_mode: host là lý do nginx gọi thẳng được 10.0.0.x mà không cần khai báo network Docker riêng — đồng thời cũng là lý do nếu chạy 2 bản trên 2 server thì KHÔNG xung đột cổng lẫn nhau (mỗi cái độc lập trên host riêng).

⑦ Hetzner Cloud Firewall — firewall-ssh

Console, áp cho 5/5 server
22/tcp   ← Any IPv4, Any IPv6
icmp     ← Any IPv4, Any IPv6
80/tcp   ← 5/15 dải Cloudflare
           (thiếu 10 dải nginx đang tin)
443/tcp  ← 15/15 dải Cloudflare
           (nginx không listen 443)
Đây là tầng lọc network TRƯỚC cả nginx — khác với set_real_ip_from (lọc ở tầng application). 2 tầng đang lệch nhau ở cổng 80: firewall chặt hơn nginx (5 dải so với 15), nên có thể chặn nhầm traffic Cloudflare thật. firewall-ssh là firewall duy nhất trong project và không có rule nào cho 6379/5432/9200/… — các port data default-deny từ Internet.

03 Kết luận chính & điểm cần xử lý

!

Điểm cần xử lý (Hetzner Firewall firewall-ssh, áp cho cả 5 server): rule :80 chỉ whitelist 5/15 dải Cloudflare trong khi nginx tin 15 dải qua set_real_ip_from — request thật qua PoP thuộc 10 dải thiếu bị DROP trước khi tới nginx (sửa trên Console, bước 0A của kế hoạch chuyển đổi); rule :22 mở cho toàn Internet (bước 0B); rule :443 có đủ 15/15 dải dù nginx không listen 443. Xem card ⑦ ở trên và rủi ro #13–14 trong Ha-Tang-Deep-Dive.html.

Kết luận chính: nginx-lb duy nhất trên V1 — SPOF của toàn hệ · frontend không nằm trong 5 server: 6 site (client, shop, agent, super-agent, admin, cashier) hosting trên Cloudflare Pages · các port data (6379/5432/9200/…) default-deny từ Internet · Dozzle (4/4) và RedisInsight báo unhealthy chỉ do healthcheck image sai — không phải sự cố. Kế hoạch xử lý: so-sanh-va-ke-hoach-chuyen-doi.html · kiến trúc đích: he-thong-dich.html.