云服务器环境就绪后,在浏览器输入公网 IP,屏幕上常会跳出一行大字:"Welcome to nginx!"。
此时容易产生三个疑问:我的网站在哪?Nginx 是做什么的?为什么几乎所有正式项目都离不开它?
本文从一个最常见的新手现象出发,梳理 Nginx 的产生背景、核心作用与实战配置。全文以「餐厅」作类比,便于建立完整心智模型。
目录
- 从一个现象说起:默认页面意味着什么
- Nginx 的诞生:高并发场景逼出来的架构
- 没有 Nginx 行不行?行,但缺少统一前台
- Nginx 的四大核心职责
- 实战:把公网流量接到后端服务
- 新手最容易踩的三个坑
- 常用命令速查
- 总结
一、从一个现象说起:默认页面意味着什么
输入公网 IP 能看到 "Welcome to nginx!",通常说明三件事:
| 现象 | 说明 |
|---|---|
| 能打开页面 | 服务器上 Nginx 已安装并处于运行状态 |
| 走的是 80 端口 | 公网链路畅通(防火墙 / 安全组已放行 80) |
| 显示的是默认页 | 尚未配置自己的站点,Nginx 用内置页面兜底响应 |
可以这样理解:餐厅门口已立好「欢迎光临」的牌子,客人推门进来却发现------只有迎宾,没有菜单,也没有通往后厨的指引。
Nginx 已经就位,但还没有被告知:客人到来后,应当被引导至哪一间「后厨」(后端服务)。这正是本文要解决的问题。
二、Nginx 的诞生:高并发场景逼出来的架构
2.1 C10K 问题
2000 年前后,主流 Web 服务器以 Apache 为代表,常见模型是:每一个连接对应一个进程或线程------类似「一位客人配一名专属服务员」。
客人不多时并无大碍。互联网流量爆发后,矛盾迅速显现:
若同一时刻有约 1 万个并发连接,就意味着近万个线程同时存在------内存消耗激增,CPU 大量时间耗在上下文切换上,服务能力急剧下降。
这就是著名的 C10K 问题(单机支撑约一万并发连接的难题)。
2.2 事件驱动的解法
2002 年,俄罗斯工程师 Igor Sysoev 为门户网站 Rambler 开发了 Nginx,并于 2004 年开源。其思路不再是「一人一客」,而是少量 worker 进程、用事件通知驱动处理:
text
Apache 常见模式: Nginx 模式:
客人 A ──► 服务员甲 客人 A ┐
客人 B ──► 服务员乙 vs 客人 B ┼──► 少量 worker
客人 C ──► 服务员丙 客人 C ┘ (有 I/O 事件再处理)
Nginx 采用 事件驱动(如 epoll)+ 固定数量的 worker 进程:不必为每个连接阻塞等待,哪个连接有数据可读/可写,就处理哪个。
结果是:同等硬件条件下可支撑更高并发,内存占用更低、稳定性更好。这也是它成为主流流量入口的重要原因------全球大量网站以 Nginx 作为对外统一入口。
三、没有 Nginx 行不行?行,但缺少统一前台
需要先纠正一个误解:Nginx 并非技术上的绝对必需品。
Spring Boot 监听 8090 时,浏览器直接访问 http://公网IP:8090 完全可以通;Node.js、Python 亦可快速起一个 HTTP 服务。
正式项目仍普遍前置 Nginx,是因为它解决的从来不是「能不能通」,而是「是否好用、是否安全、是否扛得住发布与并发」。
把服务器比作一家餐厅:
| 角色 | 对应组件 | 擅长什么 |
|---|---|---|
| 后厨 | Java / Go / Node 等业务服务 | 业务逻辑(「做菜」) |
| 前台 / 迎宾 / 保安 / 传菜口 | Nginx | 接客、分流、防护、静态资源 |
为何几乎总要这个「前台」?可概括为六点:
1. 80 / 443 这个「大门牌号」通常只能挂一个进程
浏览器访问 http://IP 默认连接 80 (HTTPS 为 443),而同一端口一般只能被一个进程占用。
- 没有 Nginx:用户需要记住
IP:8090,端口散乱,业务端口直接暴露在公网; - 有了 Nginx:由 Nginx 占用大门,再按规则将请求转到 8090、8091 等内部端口。
2. 后厨直接对外,等于扩大攻击面
业务端口暴露公网后,更容易成为扫描、撞库与漏洞利用的目标。Nginx 作为成熟的流量入口,攻击面相对可控,并便于叠加限流、IP 策略等防护。
保安的工作,不宜长期交给厨师。
3. 一台机器往往要承载多个站点或服务
text
admin.example.com → 管理后台 (8090)
api.example.com → 用户接口 (8091)
静态路径 /static/ → 磁盘文件直出
没有统一入口,多服务在「一个公网端口」上共存会变得困难。
4. HTTPS 适合集中在入口处理
证书部署与 TLS 加解密集中在 Nginx,后端可继续使用内网 HTTP,业务代码改动面小。
5. 静态资源不必每次惊动后厨
图片、CSS、JS 等静态内容由 Nginx 直接返回,并配合缓存与 gzip,通常比业务框架亲自吐文件更高效。
6. 发布与重启时,入口仍可对外给出可控响应
后端升级、重启的短暂窗口内:
- 没有 Nginx:用户直接看到无法访问;
- 有了 Nginx:可返回维护页,或将流量切到其他健康节点。
四、Nginx 的四大核心职责
4.1 反向代理:入口的主业
这是现代架构中 Nginx 最常见的角色。先分清「正向」与「反向」:
text
正向代理:替【客户端】访问外部 ------ 例如内网统一出口
(客户端知道目的地,但需经代理出去)
反向代理:替【服务端】接收访问 ------ 用户访问 80,由 Nginx 转到内部 8090
(客户端通常感知不到真实后端端口)
请求路径示意:
text
用户浏览器
│ http://example.com/ (80)
▼
Nginx ──────────► Spring Boot (127.0.0.1:8090)
◄────────── 响应原路返回
后端绑定 127.0.0.1 时,不直接暴露公网,攻击面明显缩小。
4.2 负载均衡:一个前台,多个后厨
单实例能力不足时,水平扩展多个节点,由 Nginx 分配请求:
nginx
upstream backend {
server 127.0.0.1:8090;
server 127.0.0.1:8091;
server 10.0.0.5:8090 weight=2; # 规格更好,多分配一些
}
server {
listen 80;
location / {
proxy_pass http://backend;
}
}
常用策略:
| 策略 | 类比 | 适用场景 |
|---|---|---|
| 轮询(默认) | 依次接单 | 节点能力接近 |
| weight | 能力强的多接 | 机器规格不一 |
| ip_hash | 同一访客尽量落同一节点 | 需要会话粘性 |
| least_conn | 优先派给当前连接更少的节点 | 请求耗时差异大 |
某节点连续失败时,可结合 max_fails / fail_timeout 等参数暂时摘除;恢复后再参与调度。需要注意:开源 Nginx 多为被动健康检查 ,主动探活通常依赖商业版或第三方能力。有状态会话更稳妥的做法是放入 Redis 等共享存储,而不是长期依赖 ip_hash。
4.3 静态资源:入口侧的「凉菜柜」
nginx
location /static/ {
alias /var/www/static/;
expires 7d;
access_log off;
}
gzip on;
gzip_types text/css application/javascript application/json;
前端构建产物、图片与下载文件,优先由 Nginx 直出。同等硬件下,静态吞吐往往明显高于由业务进程代为读写磁盘。
4.4 HTTPS 卸载:证书与加密集中处理
nginx
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/nginx/cert/example.com.pem;
ssl_certificate_key /etc/nginx/cert/example.com.key;
location / {
proxy_pass http://127.0.0.1:8090; # 对内继续 HTTP
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}
对外加密,对内简化。证书更新通常只需改 Nginx 一处,后端可无感。
五、实战:把公网流量接到后端服务
场景:本机 Spring Boot 监听 127.0.0.1:8090,希望通过公网 IP 的 80 端口访问。
5.1 最小可用配置
编辑 /etc/nginx/conf.d/default.conf(或站点独立 conf):
nginx
server {
listen 80;
server_name _; # 暂用 IP 访问时可保持默认
client_max_body_size 50m;
location / {
proxy_pass http://127.0.0.1:8090;
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 $scheme;
}
}
proxy_set_header 不宜省略:若不传,后端看到的客户端 IP 往往是 127.0.0.1(Nginx 自身),日志、风控与部分鉴权会失真------相当于客人从哪来、是否 HTTPS,前台没有如实转达。
5.2 生效步骤
bash
nginx -t # 先做语法检查
nginx -s reload # 再平滑重载(优先于 restart)
完成后再次访问公网 IP,应进入业务页面,而不是 Welcome 页。若仍看到默认页,检查是否另有 default_server 抢占了匹配。
5.3 按路径拆分多服务(可选)
nginx
location /api/ {
proxy_pass http://127.0.0.1:8090/;
}
location /admin/ {
proxy_pass http://127.0.0.1:8091/;
}
location / {
root /var/www/web;
try_files $uri $uri/ /index.html;
}
六、新手最容易踩的三个坑
坑 1:SSE / WebSocket 被默认超时或缓冲打断
典型现象 :直连 8090 时 SSE 正常;经 Nginx 后约 60 秒断开,后端出现 Broken pipe。
原因在于:默认配置偏短连接场景------可能开启缓冲,且读超时默认较短。SSE / WebSocket 需要长时间挂起、尽快透传。
nginx
location /sse/ {
proxy_pass http://127.0.0.1:8090;
proxy_http_version 1.1;
proxy_set_header Connection '';
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
WebSocket 通常还需:
nginx
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
默认值面向普通短请求;长连接必须显式声明「不要按短请求方式打断」。
坑 2:改完配置未先执行 nginx -t
直接对错误配置 reload,轻则新配置未生效,重则服务异常、对外 502。建议形成习惯:先 -t,再 reload。
坑 3:proxy_pass 末尾斜杠改变上游路径
nginx
# 请求 /api/user → 上游多为 /api/user
location /api/ {
proxy_pass http://127.0.0.1:8090;
}
# 请求 /api/user → 上游多为 /user(location 前缀被替换)
location /api/ {
proxy_pass http://127.0.0.1:8090/;
}
末尾是否带 /,会改变 URI 拼接规则。配置变更后务必用真实路径实测一次。
七、常用命令速查
| 命令 | 作用 |
|---|---|
nginx -t |
校验配置语法 |
nginx -s reload |
平滑重载配置 |
nginx -s stop |
立即停止 |
systemctl start/enable nginx |
启动 / 开机自启 |
tail -f /var/log/nginx/access.log |
访问日志 |
tail -f /var/log/nginx/error.log |
排障首选 |
nginx -V |
查看版本与编译模块 |
八、总结
回扣开篇三个问题:
-
为何 IP 访问到的是默认页?
Nginx 已运行且 80 可达,但尚未配置业务站点,因而用内置页兜底。
-
访问网站是否必须使用 Nginx?
技术上不必;直连后端端口亦可。正式环境需要统一入口、安全边界与发布弹性时,几乎都会前置 Nginx。
-
Nginx 的本质是什么?
蹲在业务服务前面的总入口:反向代理(引流)、负载均衡(分摊)、静态资源(直出)、HTTPS(终端加密),并可叠加限流等防护。
其分工原则也值得后端记住:
让合适的组件做合适的事。 业务服务专注领域逻辑;连接管理、并发调度与入口防护,交给为高并发入口设计的 Nginx。
下次再看到 "Welcome to nginx!",它不再只是一块空白默认页,而是一位已经就位、等待你配置路由规则的入口组件。