🚀 第01章 · Nginx 架构与安装

安装/目录结构/工作模型

Nginx 架构与安装

这一章先把 Nginx 讲清楚:它到底是什么、为什么这么多站点用它的"事件驱动"模型、装好之后文件都放在哪、配置文件长什么样。学完你就明白,后面所有章节讲的虚拟主机、反向代理、负载均衡,都长在同一个骨架上。

为什么是 Nginx

传统 Web 服务器(如 Apache)是"进程/线程模型"——每一个请求独占一个进程或线程,连接多了内存和上下文切换成本迅速上升。Nginx 不一样,它天生为高并发、低内存而生,只处理两件事:

优势 说明
事件驱动异步 IO 单个进程同时管理成千上万连接,不阻塞等待
反向代理/负载均衡 天然适合当"网关",转发请求到后端应用
静态资源极快 直接由 Nginx 发送文件,不经过后端语言
配置简单可读 层级化指令,一个配置文件就能看懂整个站点架构

这正是现实服务器里的分工:外层 Nginx 统一终止 TLS、转发请求到 127.0.0.1 上的各种后端服务。Nginx 在前面"站岗",真正的业务逻辑在后面的 Node/Python/Go/GitLab 里。

工作模型:master + worker

Nginx 启动后是一个 master 进程加若干 worker 进程:

master 进程                    负责读取配置、管理 worker、优雅重启
 ├── worker 进程 (N 个)         真正处理请求,数量 = worker_processes
 ├── cache manager 进程         管理代理缓存(proxy_cache)
 └── cache loader 进程          启动时把缓存目录加载进内存

打开本机的配置看一眼:

# worker 进程数量
grep -n 'worker_processes' /etc/nginx/nginx.conf

输出 worker_processes auto;,意思是让 Nginx 自动按 CPU 核数决定 worker 数量。auto 是省心的选择;也可以手动填一个数字,比如 4。

理解 worker 之间是平等的,都往同一个监听端口上 accept。所有 worker 共享配置,但各自独立处理连接。所以:想调并发上限,改 events 块里的 worker_connections,而不是疯狂加 worker。

事件驱动是怎么做到的

Nginx 用的是 OS 的 IO 多路复用机制(Linux 上是 epoll)。它把"等数据到达"这一步交给内核,内核一旦发现某个 socket 有数据可读/可写,就通知 Nginx。因此在等待网络 IO 时,Nginx 的 worker 不会被"卡住",而是继续处理别的请求。

events {
    worker_connections 768;   # 单个 worker 能同时处理的连接数
    # multi_accept on;        # 一次 accept 多个新连接(默认关,见注释)
}

注意 worker_connections 是"每个 worker"的连接上限。Nginx 理论单机支撑的连接数 ≈ worker_processes × worker_connections。而且每个连接默认还会占用文件描述符,记得检查系统的 ulimit -n。

Ubuntu 上的目录结构

本机是 Ubuntu 24.04、通过 apt 安装的 nginx 1.24.0,文件分散在几个约定位置:

路径 作用
/etc/nginx/nginx.conf 主配置文件,Nginx 从这里开始读
/etc/nginx/mime.types 扩展名 → MIME 类型映射表
/etc/nginx/sites-available/ "可用的"站点配置,默认不加载
/etc/nginx/sites-enabled/ "启用的"站点配置,被 nginx.conf include
/etc/nginx/conf.d/ 通用片段,nginx.conf 无条件 include
/var/log/nginx/ access_log / error_log 日志目录
/run/nginx.pid Nginx master 进程号(重载/停止信号用它)
/usr/sbin/nginx Nginx 二进制本体

这里要特别说明 sites-available 和 sites-enabled 的关系:配置写在 available,再软链接到 enabled 才算启用。看本机的链接:

ls -l /etc/nginx/sites-enabled/
bangdream.xyz.conf  -> /etc/nginx/sites-available/bangdream.xyz.conf
dsh.bangdream.xyz.conf -> /etc/nginx/sites-available/dsh.bangdream.xyz.conf
gitlab.bangdream.xyz.conf -> /etc/nginx/sites-available/gitlab.bangdream.xyz.conf
lovelive.top.conf    -> /etc/nginx/sites-available/lovelive.top.conf

而 nginx.conf 里用 include /etc/nginx/sites-enabled/*; 把这些"已启用"的文件读进来。所以停用一个站点,把软链接删掉、再 nginx -s reload 即可,不必改配置文件本身。

安装与版本

# 更新索引后安装
sudo apt update
sudo apt install -y nginx

# 查看版本
nginx -v

# 查看编译参数(看它支持哪些模块)
nginx -V 2>&1 | tr ' ' '\n' | head

本机输出 nginx version: nginx/1.24.0 (Ubuntu)。nginx -V 会列出编译进的模块,比如 --with-http_ssl_module 说明支持 TLS,--with-stream 说明支持 TCP/UDP 四层代理。

易错 nginx -v 只显示版本号,nginx -V(大写)才显示编译参数和模块列表。排错时想知道某个指令是否可用,先 nginx -V 看模块。

nginx.conf 的结构

配置文件是层级嵌套的:外层有一个全局 http {} 块,里面是 server {},再里面是 location {}。本机的主配置拆开看:

user www-data;                    # worker 进程以哪个用户运行(低权限更安全)
worker_processes auto;            # 每核一个 worker
pid /run/nginx.pid;               # master 进程号存放位置
error_log /var/log/nginx/error.log;  # 全局错误日志

events {
    worker_connections 768;
}

http {
    map $http_upgrade $connection_upgrade {
        default upgrade;
        ''      close;
    }

    sendfile on;                  # 静态文件由内核直接搬运,跳过用户态缓存
    tcp_nopush on;
    default_type application/octet-stream;
    access_log /var/log/nginx/access.log;

    gzip on;

    include /etc/nginx/mime.types;
    include /etc/nginx/conf.d/*.conf;      # 通用片段
    include /etc/nginx/sites-enabled/*;    # 各虚拟主机配置
}

http {} 内的 map 是一段很实用的逻辑:它会根据请求头 Upgrade 的值,产出变量 $connection_upgrade。如果客户端请求了 WebSocket(Upgrade 非空),就取 upgrade;否则取 close。这个变量在后面 GitLab 反代时被用来设置 Connection 头。

理解 include 是拼接文件的手段。把配置拆到 sites-available、conf.d,是为了按站点和职责分离,而不是全部堆在一个大文件里。这也是你日后加站点的方式:新建一个 *.conf,软链接进 sites-enabled,重载即可。

启停与重载

Ubuntu 上用 systemd 管理(也直接支持 Nginx 自带的信号):

sudo systemctl enable --now nginx   # 开机自启并启动
sudo systemctl restart nginx        # 完全重启(会断开连接)
sudo systemctl reload nginx         # 优雅重载,不中断现有连接
sudo systemctl status nginx         # 查看运行状态

# 或者直接用 nginx 自带命令(依赖 master 进程)
sudo nginx -s quit     # 优雅退出
sudo nginx -s stop     # 立即退出
sudo nginx -s reload   # 重新加载配置

易错 reload 与 restart 有本质区别:restart 会先停掉所有 worker、断开正在处理的连接;reload 是"原地换血",旧 worker 处理完手头请求再退,新 worker 用新配置接管。线上改配置永远优先用 reload。

验证是否在跑

ps -ef | grep nginx | grep -v grep
# root      master 进程
# www-data  worker 进程...

ss -lntp | grep ':80 '     # 监听 80 端口
ss -lntp | grep ':443'     # 监听 443 端口

看到 master 以 root、worker 以 www-data 运行,是正常的。master 需要 root 才能开 80/443 低端口,真正的处理交给降权后的 worker,这也是一种安全设计。

小结

这一章建立了阅读后续章节需要的全部背景:Nginx 是事件驱动的网关,由 master 加若干 worker 组成;配置按 http → server → location 嵌套;Ubuntu 下站点配置走 sites-available + sites-enabled 软链;改完配置用 reload 而不是 restart。下一章,我们把目光从全局骨架转向单个 server 块——虚拟主机是怎么区分不同域名的。