nginx 基础入门实战

之前一直在用hexo +Vercel部署博客,但最近突然想着在vps上部署自己的博客,再有域名加持,让简单的事变得没有那么简单。这个时候就想到了nginx反向代理。因此写一篇文章梳理一下

作用

  • 反向代理: 隐藏后端服务器,提高安全性,实现负载均衡。
  • 负载均衡: 将请求分发到多个后端服务器,提高系统吞吐量和可用性。
  • 静态资源缓存: 缓存图片、CSS、JavaScript 等静态文件,减轻后端服务器压力,加快访问速度。
  • SSL/TLS 加密: 提供 HTTPS 支持,保护数据传输安全。
  • WebSockets 支持: 实现实时双向通信。

原理

  • 事件驱动(Event-driven)架构:

    • 传统服务器(如 Apache)通常采用多进程或多线程模型。每个连接都需要一个独立的进程或线程来处理,当连接数很多时,会消耗大量系统资源。
    • Nginx 采用事件驱动模型。想象一下,一个服务员(Nginx 工作进程)可以同时服务多个餐桌(连接)。他不会一直站在一个餐桌旁等待,而是哪个餐桌有需要(事件发生,如顾客点餐、上菜)就去处理哪个。这种方式大大减少了资源消耗。
    • Nginx 使用像 epoll (Linux)、kqueue (FreeBSD) 和 select/poll 这样的 I/O 多路复用技术来实现事件驱动。这些技术允许一个进程监控多个连接上的事件,并在事件发生时进行处理。
  • 异步非阻塞(Asynchronous Non-blocking)I/O:

    • 异步: 服务员(Nginx)告诉厨房(后端服务器)做菜后,不会傻傻地站在那里等,而是去服务其他餐桌。厨房做好菜后会通知服务员。
    • 非阻塞: 服务员在等待厨房做菜的过程中,不会被“阻塞”住,可以处理其他事务。
    • 传统的同步阻塞 I/O 模型中,一个进程在等待 I/O 操作完成时会被阻塞,无法做其他事情。而 Nginx 的异步非阻塞 I/O 模型则允许进程在等待 I/O 操作时,可以继续处理其他请求。
  • Master-Worker 进程模型:

    • Nginx 启动时,会创建一个 Master 进程和多个 Worker 进程。
      • Master 进程: 像餐厅老板,负责管理(如加载配置、启动/停止 Worker 进程、监控 Worker 进程状态)。
      • Worker 进程: 真正的服务员,负责处理客户端请求。
    • Master进程不处理客户端的请求。它只负责管理工作进程。比如当Master进程收到reload配置文件的命令以后,会先检查配置文件的正确性。然后通知worker进程。worker进程收到以后,会继续处理未完成的请求,处理完成以后,退出进程,根据新的配置文件启动新的worker进程。
  • 高效的内存管理:

    • Nginx 使用内存池(memory pool)来管理内存。这样可以减少内存碎片,提高内存分配和释放的效率。

3. Nginx 的核心组件

  • 核心模块(Core Module): 提供 Nginx 的基本功能,如进程管理、配置解析、错误处理等。
  • 事件模块(Event Module): 实现事件驱动机制,处理网络连接和事件。
  • HTTP 模块: 处理 HTTP 请求和响应。
  • 邮件模块(Mail Module): 处理邮件代理相关功能。
  • 流模块(Stream Module): 提供 TCP 和 UDP 流量的反向代理和负载均衡功能。

反向代理

这是nginx最常见的功能,那么为什么需要反向代理。它不只是隐藏后端服务器这么简单,还能防止攻击,过滤恶意请求。同时他还能处理SSL/TLS加密解密。
假设你有一个在线购物网站,有多个后端服务器分别处理商品展示、用户登录、购物车、订单支付等功能。

  • 如果没有反向代理,客户端需要分别与这些服务器通信,配置复杂,而且每个服务器都需要直接暴露在公网上,安全风险高。
  • 有了反向代理,客户端只需要与反向代理通信,反向代理根据请求的 URL 或其他规则,将请求转发到相应的后端服务器。反向代理还可以缓存静态资源,处理 SSL 加密,实现负载均衡,提高系统的安全性、性能和可用性。

实现

1. 目标
假设你有一个 Web 应用(比如一个 Node.js 应用)运行在本地的 3000 端口。你希望通过 Nginx 将对你的域名(例如 example.com)的访问转发到这个应用。

2. 基础配置

步骤 1: 找到 Nginx 的配置文件。通常位于以下路径之一:

  • /etc/nginx/nginx.conf
  • /usr/local/nginx/conf/nginx.conf
  • /usr/local/etc/nginx/nginx.conf

步骤 2: 使用文本编辑器打开配置文件。

步骤 3: 找到 http 块,在其中添加一个 server 块。如果已经有 server 块,你可以直接修改它,或者添加一个新的。

1
2
3
4
5
6
7
8
9
10
11
12
http {
# ... 其他配置 ...

server {
listen 80; # 监听 80 端口(HTTP 默认端口)
server_name example.com; # 将 example.com 替换为你的域名或服务器 IP

location / {
proxy_pass http://localhost:3000; # 将请求转发到本地 3000 端口
}
}
}

步骤 4: 保存配置文件。

步骤 5: 检查配置文件的语法是否正确:

1
sudo nginx -t

如果配置正确,你会看到类似这样的输出:

1
2
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

步骤 6: 重新加载 Nginx 配置,使更改生效:

1
sudo nginx -s reload

3. 配置解读

  • listen 80;: Nginx 将监听 80 端口,处理 HTTP 请求。
  • server_name example.com;: 设置你的域名或服务器 IP。客户端通过这个域名或 IP 访问时,Nginx 会处理请求。
  • location / { ... }: 定义如何处理匹配的请求。/ 表示匹配所有请求。
  • proxy_pass http://localhost:3000;: 这是反向代理的核心!它告诉 Nginx 将请求转发到 http://localhost:3000

4. 常见问题排查

  • 无法访问网站:
    • 确保你的域名已正确解析到服务器 IP。
    • 检查服务器防火墙是否允许 80 端口的流量。
    • 确保你的后端应用正在运行,并且监听正确的端口(本例中是 3000)。
  • Nginx 报错:
    • 仔细检查 nginx -t 命令的输出,它会告诉你配置文件的哪一行有错误。
    • 查看 Nginx 的错误日志(通常位于 /var/log/nginx/error.log),可能会有更详细的错误信息。

6. 常用高级配置

6.1. proxy_set_header:传递请求头

默认情况下,Nginx 转发请求时会修改一些请求头。proxy_set_header 指令可以让你控制传递给后端服务器的请求头。

1
2
3
4
5
6
7
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host; # 传递原始的 Host 头
proxy_set_header X-Real-IP $remote_addr; # 传递客户端的真实 IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 传递代理链
proxy_set_header X-Forwarded-Proto $scheme; # 传递协议(http 或 https)
}

X-Forwarded-For

假如客户端请求到达服务器之前,中间经过了 3 个代理服务器,那么每一个代理服务器都会把其的 IP 地址追加到 X-Forwarded-For中,像这样:

1
X-Forwarded-For: client, proxy1, proxy2

$proxy_add_x_forwarded_for 变量会自动添加当前服务器的 IP 地址到 X-Forwarded-For 头部。

6.2. proxy_redirect:修改重定向

如果后端应用返回重定向响应(例如 302 Found),proxy_redirect 可以修改响应头中的 Location 字段。

1
proxy_redirect off;  # 通常设置为 off,除非你有特殊需求

6.3. 负载均衡(多个后端服务器)

如果有多个后端服务器,可以使用 upstream 块定义服务器组,实现负载均衡。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
upstream backend {
server backend1.example.com;
server backend2.example.com;
# 可以添加更多服务器
}

server {
listen 80;
server_name example.com;

location / {
proxy_pass http://backend; # 注意这里使用了 upstream 名称
# ... 其他配置 ...
}
}

负载均衡算法:

  • round_robin (默认):轮询,依次将请求分发到每个服务器。
  • least_conn:最少连接,将请求分发到当前连接数最少的服务器。
  • ip_hash:根据客户端 IP 哈希,将同一个 IP 的请求分发到同一个服务器(用于会话保持)。

权重:

1
2
3
4
upstream backend {
server backend1.example.com weight=5; # backend1 处理更多请求
server backend2.example.com;
}

6.4. 启用 HTTPS

  1. 获取 SSL/TLS 证书: 可以从 Let’s Encrypt (免费) 或其他证书颁发机构获取。

  2. 配置 Nginx:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
server {
listen 443 ssl; # 监听 443 端口,启用 SSL
server_name example.com;

ssl_certificate /path/to/your/fullchain.pem; # 证书文件路径
ssl_certificate_key /path/to/your/privkey.pem; # 私钥文件路径

location / {
proxy_pass http://localhost:3000;
# ... 其他配置 ...
}
}

# 可选:将 HTTP 请求重定向到 HTTPS
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}

重要提示:

  • /path/to/your/ 替换为你的证书和私钥的实际路径。
  • 建议配置强密码和安全的密钥存储。
  • 启用ssl_protocolsssl_ciphersssl_prefer_server_ciphers

常见命令

好的,在掌握了 Nginx 反向代理的配置之后,熟悉常用的 Nginx 命令对于日常管理和维护至关重要。下面列出了一些最常用的 Nginx 命令及其用法:

1. 启动、停止、重启 Nginx

  • 启动 Nginx:

    1
    2
    3
    sudo systemctl start nginx  # 使用 systemd 管理的系统(如 Ubuntu 16.04+、Debian 8+、CentOS 7+)
    sudo service nginx start # 使用 SysVinit 管理的系统(如 Ubuntu 14.04、Debian 7)
    sudo nginx # 直接启动(通常不推荐,除非你知道自己在做什么)
  • 停止 Nginx:

    1
    2
    3
    sudo systemctl stop nginx
    sudo service nginx stop
    sudo nginx -s stop # 强制停止
    选项 描述
    stop 快速关闭
    quit 优雅的关闭
    reload 重新加载配置文件,优雅的停止旧的进程,开启新的进程
    reopen 重新打开日志文件
  • 重启 Nginx:

    1
    2
    3
    sudo systemctl restart nginx
    sudo service nginx restart
    sudo nginx -s reload # 平滑重启(推荐,不会中断现有连接)
  • 优雅地停止:

    1
    sudo nginx -s quit #等待工作进程处理完成当前连接后关闭

2. 检查 Nginx 状态

1
2
sudo systemctl status nginx
sudo service nginx status

这些命令会显示 Nginx 的运行状态(是否正在运行、进程 ID、启动时间等)以及最近的日志。

3. 测试 Nginx 配置

1
sudo nginx -t

这个命令非常重要!它会检查你的 Nginx 配置文件(通常是 /etc/nginx/nginx.conf/etc/nginx/conf.d/ 下的文件)的语法是否正确。在每次修改配置文件后,都应该先运行这个命令进行检查,然后再重新加载配置。

如果配置有错误,Nginx 会给出错误提示,并指出错误所在的行号。

4. 重新加载 Nginx 配置

1
sudo nginx -s reload

这个命令会平滑地重新加载 Nginx 配置,而不会中断现有的连接。Nginx 会启动新的 worker 进程来处理新的请求,同时让旧的 worker 进程继续处理完已有的连接,直到处理完毕后退出。

5. 查看 Nginx 版本

1
2
nginx -v   # 显示简要版本信息
nginx -V # 显示详细版本信息和编译选项

6. 查看 Nginx 进程

1
ps aux | grep nginx

这个命令会列出所有包含 “nginx” 关键字的进程,你可以看到 Nginx 的 master 进程和 worker 进程。

7. 查看 Nginx 日志

Nginx 有两种主要的日志:

  • 访问日志 (access log): 记录每个客户端请求的详细信息(IP 地址、时间、请求的 URL、状态码、浏览器信息等)。
    • 默认位置通常是 /var/log/nginx/access.log,但可以在配置文件中自定义。
  • 错误日志 (error log): 记录 Nginx 运行过程中的错误信息,以及一些警告和调试信息。
    • 默认位置通常是 /var/log/nginx/error.log,也可以在配置文件中自定义。

你可以使用 taillesscat 等命令查看这些日志:

1
2
sudo tail -f /var/log/nginx/access.log  # 实时查看访问日志的最新内容
sudo less /var/log/nginx/error.log # 查看错误日志

8. 指定配置文件启动

1
sudo nginx -c /path/to/your/nginx.conf # 指定配置文件

9. 帮助命令

1
nginx -h  # 或者 nginx -?

显示 Nginx 的命令行选项帮助信息。

总结和提示

  • 使用 sudo 大多数 Nginx 命令需要 root 权限才能执行,所以通常要加上 sudo
  • systemctl vs service 根据你的操作系统使用 systemctlservice 命令。systemctl 是较新的系统管理工具,而 service 是传统的 SysVinit 工具。
  • 先测试,再重载: 每次修改 Nginx 配置文件后,务必先使用 nginx -t 测试配置是否正确,然后再使用 nginx -s reload 重新加载配置。
  • 日志很重要: 经常查看 Nginx 的访问日志和错误日志,可以帮助你了解网站的运行情况,排查问题。
2019-2025 Sean Yam