安装
sudo apt install -y nginx
sudo systemctl start nginx
sudo systemctl enable nginx
sudo systemctl status nginx
什么是Nginx
这是一个非常好的面试复盘题!
首先纠正一个概念:Nginx 绝对不仅仅 是用来“更改页面”(重定向/URL重写)和“负载均衡”的。虽然这两点它做得很好,但如果只回答这两个,面试官会觉得你对它的理解还停留在“配置工”的层面。
对于 Java 后端开发来说,Nginx 是整个 Web 架构的咽喉和守门人。
为了让你下次面试能**“降维打击”**,我帮你把 Nginx 拆解成 “四大核心功能 + 一个底层架构”。
1. 核心功能一:反向代理 (Reverse Proxy) —— “大管家”
这是 Nginx 最本质的角色。
-
正向代理:你需要梯子访问 Google,梯子就是正向代理(代理的是客户端)。
-
反向代理:用户访问你的网站
dx.w1lsp0.top,用户不知道后面是 Tomcat、是 Go 还是 Python,只知道找 Nginx。Nginx 接收请求后,转身去内网找真正的服务器拿数据,再给用户。
面试话术:
“Nginx 作为反向代理,隐藏了后端服务器的真实 IP,提高了安全性。它就像一个大管家,用户只跟管家打交道,见不到里面的主人(Tomcat)。”
2. 核心功能二:负载均衡 (Load Balancing) —— “交通指挥官”
这就是你提到的功能。当你以后业务做大了,一个 Tomcat 扛不住了,你部署了 3 个 Tomcat(集群)。Nginx 负责把流量分给它们。
面试加分项(必须背下来的策略):
-
轮询 (Round Robin):默认方式。你一个,我一个,它一个,公平分配。
-
权重 (Weight):服务器 A 性能强(8核),服务器 B 弱(2核)。给 A 权重设 4,B 设 1。Nginx 就会多往 A 发请求。
-
IP Hash:(重点) 让同一个 IP 的用户,永远访问同一台服务器。这能解决Session 共享的问题(虽然现在都用 Redis 存 Session 了,但这个策略面试必问)。
3. 核心功能三:动静分离 (Static Content Serving) —— “专业的事专业人做”
这是你现在 Quartz 博客正在用的功能!
-
Tomcat/Java:擅长处理逻辑(算钱、查库、登录),但是处理图片、CSS、HTML 非常慢,那是“大材小用”。
-
Nginx:处理静态文件(图片、CSS、JS)的速度是 Tomcat 的 几倍甚至几十倍。它是基于 C 语言写的,IO 效率极高。
应用场景:
把所有的 .jpg、.css、.js 扔给 Nginx 直接读取硬盘返回;只有 /api/login 这种请求才放行给 Tomcat。
面试话术:
“我在项目中利用 Nginx 做动静分离。将静态资源交给 Nginx 处理,Tomcat 只负责业务逻辑,这样大大减轻了后端服务器的压力,提升了系统的吞吐量。”
4. 核心功能四:高性能扩展 (Gzip / SSL / Cache) —— “BUFF 加持器”
这就是我们刚才做的事!
-
Gzip 压缩:你刚才配置的,把 1MB 的文件压成 300KB,省带宽,提速度。
-
SSL 卸载:配置 HTTPS 证书。解密 HTTPS 是很耗 CPU 的,这活儿让 Nginx 干,Tomcat 就能专心跑业务,不用管加密解密。
-
限流/黑名单:限制某个 IP 一秒钟只能访问 10 次,防止被刷接口。
5. 底层原理:为什么 Nginx 这么快? (Epoll / Master-Worker) —— “面试杀手锏”
如果面试官问:“为什么 Nginx 能抗住 5万并发,而 Apache/Tomcat 不行?”
你要回答这两个关键词:
-
异步非阻塞 (Event-driven):
-
Tomcat (传统模式):像“服务员一对一服务”。一个客人来,分配一个服务员(线程)一直死等他点菜、吃完。客人多了,服务员不够用,由于线程切换开销大,服务器就崩了。
-
Nginx (Epoll 模型):像“收银员”。一个收银员处理所有人的排队。你点菜慢?你去旁边想好了再来,我先给下一位结账。它不需要为每个连接创建一个线程,而是用一个进程处理成千上万个连接。
-
-
Master-Worker 进程模型:
-
一个 Master(老板)负责管理配置。
-
多个 Worker(打工人)负责真正干活。Worker 数量通常等于 CPU 核数,完全利用多核性能,没有线程切换的浪费。
-
🎤 总结:下次面试官问“你了解 Nginx 吗?” 该怎么说?
请背诵并根据自己的情况微调下面这段话:
“了解的。在我之前的项目(比如那个 DDD 抽奖平台或个人博客)中,Nginx 主要承担了 网关 的角色。
反向代理与动静分离:我使用 Nginx 代理前端的静态资源(HTML/CSS/JS),利用其高效的 IO 性能提升加载速度,同时将
/api接口请求转发给后端的 SpringBoot 集群,实现动静分离。性能优化:我配置了 Gzip 压缩,将文本类资源体积减少了 70%,有效节省了服务器带宽。同时配置了 Keep-alive 长连接,减少了 TCP 握手的开销。
架构理解:我还了解 Nginx 底层是基于 Epoll 的异步非阻塞模型 和 Master-Worker 进程机制,这使得它在处理高并发连接时,内存占用极低且稳定性极高。
(如果还想秀):如果是集群环境,我还会配置 Upstream 实现负载均衡,通过 IP Hash 或 Weight 策略来分配流量。”
你看,这样回答,是不是比“只负责改页面”要专业 100 倍? 😎
Tomcat是什么
这是一个非常敏锐的问题!你正在触及 Web 架构的核心:分层。
简单直接的回答:
-
Tomcat 是后端服务器吗? 是的,但它更准确的名字叫 “Java 应用服务器”(或者 Servlet 容器)。它的核心职责是**“跑 Java 代码”**。
-
Nginx 不就是安装在服务器的软件吗? 完全正确!Tomcat 和 Nginx 都是安装在你那台 Linux 云服务器上的软件。
那为什么同一个服务器上要装两个“服务器软件”?它们俩到底是什么关系?
我用一个**“餐厅模型”**来帮你彻底理清这个关系,面试时用这个比喻绝对满分。
1. 餐厅模型:Nginx vs Tomcat
想象你的 Linux 云服务器就是一家餐厅。
Nginx = 前台/服务员 (Web Server)
-
它的特点:动作极快,抗压能力强,长得帅(资源占用少)。
-
它的工作:
-
客人进门,它负责接待(反向代理)。
-
客人要喝水、要菜单(静态资源:HTML/图片/CSS),它直接从柜台拿给客人,不需要进厨房。
-
客人太多,它负责安排座位,别让大家挤在一起(负载均衡)。
-
-
它的局限:它不会做饭! 如果客人点了一份“宫保鸡丁”(需要计算的 Java 业务逻辑,比如登录、查数据库),服务员是做不出来的。
Tomcat = 后厨/大厨 (Application Server)
-
它的特点:手艺精湛,懂复杂的烹饪技巧(Java/Spring Boot),但动作稍微慢点,抗压能力不如前台。
-
它的工作:
-
专门处理服务员(Nginx)递进来的菜单。
-
切菜、炒菜、放盐(执行 Java 代码、连接数据库 MySQL、进行逻辑运算)。
-
把做好的菜(JSON 数据/动态页面)端给服务员。
-
-
它的局限:如果让大厨去门口发传单(处理高并发 HTTP 连接)或者去倒水(处理静态图片),那是大材小用,而且效率极低。
2. 它们是如何配合的? (动静分离)
这就是我们常说的架构图:
-
用户 (Browser) 发起请求:
www.xinduan.top。 -
Nginx (80/443端口) 拦截请求:
-
如果是
avatar.jpg(你的头像):Nginx 直接从硬盘拿给你,耗时 1ms。 -
如果是
/api/login(登录接口):Nginx 转身把请求转发给身后的 Tomcat。
-
-
Tomcat (8080端口) 收到请求:
-
启动 Java 线程,运行 Spring Boot 代码,查 MySQL 数据库,验证密码。
-
生成结果:“登录成功”。
-
把结果还给 Nginx。
-
-
Nginx 把结果返回给用户。
3. 灵魂拷问:为什么 Spring Boot 内置了 Tomcat?
你可能会问:“我写 Spring Boot 的时候,也没装 Tomcat 啊,直接 Run 就行了?”
-
以前 (SSM 时代):我们需要先下载安装一个 Tomcat 软件,然后把 Java 代码打成
.war包扔进去跑。 -
现在 (Spring Boot 时代):Spring Boot 为了方便,直接把 Tomcat 的核心代码作为 Jar 包嵌入进来了。
- 当你运行
java -jar app.jar时,其实你就启动了一个**“内嵌版”的 Tomcat**。
- 当你运行
4. 面试必问:既然 Tomcat 能处理 HTTP,为什么还要 Nginx?
既然 Tomcat 也能直接给用户返回网页,为什么还要在前面挡一层 Nginx?
| 维度 | 只用 Tomcat (裸奔) | Nginx + Tomcat (黄金搭档) |
|---|---|---|
| 静态资源性能 | 慢,Tomcat 处理图片IO效率低 | 快,Nginx 基于 C 语言,IO 性能是 Tomcat 的 10 倍以上 |
| 抗并发能力 | 几百并发可能就卡顿 | 几万并发 轻松抗住 (Nginx 处理连接,Tomcat 只处理逻辑) |
| 安全性 | 暴露了真实的 Java 端口 (8080) | 隐藏 了后端端口,外网只看到 Nginx (80/443) |
| 扩容 | 只能垂直升级服务器 | 可以轻松配成 集群 (1个 Nginx 对应 3个 Tomcat) |
5. 总结
-
Tomcat:是后端应用服务器,专门跑 Java 代码的。它是你的业务逻辑运行的地方。
-
Nginx:是Web 服务器/反向代理服务器,专门处理 HTTP 连接和静态资源的。它是整个系统的“大门”。
-
它们的关系:Nginx 是 Tomcat 的保护伞和加速器。
下次面试官问你,你可以自信地说:
“Tomcat 负责处理复杂的 Java 业务逻辑(动态请求),而 Nginx 负责处理静态资源和请求转发(反向代理)。这样的组合既保证了后端逻辑的执行能力,又利用 Nginx 的高并发特性极大提升了系统的吞吐量。”
是不是清晰多了?
为什么不能暴露 ip,要用 nginx
这是一个非常深刻且直击 网络安全架构核心 的问题!
简单直接的回答:是的,你的理解基本正确,但大厂(比如 Google)的架构会更复杂一些。
暴露真实 IP 就像是把自家的保险柜直接扔在大街上,虽然你有钥匙(密码),但别人可以搬炸药去炸(DDoS)、拿听诊器听(扫描漏洞)、甚至把锁眼堵住(消耗连接数)。
我们分两部分来讲:为什么要隐藏 IP 以及 Google Gemini 是怎么做的。
1. 💀 为什么绝对不能暴露真实 IP?
假如你的后端服务器(Tomcat/Java)直接暴露公网 IP,会发生什么?
A. DDoS 攻击(最致命)
这是最简单的攻击方式。你的服务器带宽只有 3Mbps。
-
如果不藏 IP:攻击者只需要租几个“肉鸡”,往你的 IP 发送 100Mbps 的垃圾流量。你的 3M 小水管瞬间被塞满,正常用户(面试官)根本连不上。
-
如果用了 Nginx/CDN:攻击者只能攻击 CDN 节点。阿里云/腾讯云的 CDN 有巨大的清洗能力(Tbps 级别),能把垃圾流量挡在外面,只把干净的请求放进来给你的 Nginx。
B. 绕过 WAF 防火墙
很多公司会在 Nginx 层部署 WAF (Web Application Firewall),用来拦截 SQL 注入、XSS 攻击。
- 如果真实 IP 暴露:黑客可以直接通过 IP 访问你的 Tomcat,完全绕过了前面那层 Nginx/WAF 的安检。就像小偷不走正门(Nginx),直接翻窗户(真实 IP)进来了。
C. 端口扫描与漏洞利用
服务器上可能不止跑了 Web 服务,还开了 22 (SSH)、3306 (MySQL) 等管理端口。
-
如果暴露 IP:黑客可以扫描你的全端口,尝试爆破 SSH 密码。
-
如果隐藏 IP:外界只能看到 CDN/Nginx 的 80/443 端口,其他端口根本扫不到(因为 Nginx 服务器和数据库服务器通常是在内网互通的)。
2. 🔍 Google Gemini 是用了 Nginx 吗?
你给出的链接 https://gemini.google.com/...,它的请求流程确实是你说的逻辑,但软件层面有所不同。
Google 不用 Nginx,他们用 GFE
Google 的体量太大,Nginx 对他们来说还不够劲(或者不符合他们的定制需求)。
他们用的是自研的 GFE (Google Front End)。但 GFE 的角色 = Nginx + 负载均衡 + WAF。
真实的流量流转路径(Gemini 为例):
-
用户浏览器: 输入
gemini.google.com。 -
DNS 解析: 告诉浏览器,去访问 IP
142.250.x.x(这是 Google 的 Anycast 边缘节点 IP,类似于 CDN,全球有很多个)。 -
GFE (类 Nginx 层):
-
边缘节点收到请求,解密 HTTPS。
-
根据 URL
/app/...判断这是 Gemini 的业务。 -
流量清洗:判断你是不是黑客。
-
-
内网传输 (RPC): GFE 通过 Google 极其恐怖的内网专线,把请求发给位于美国某个数据中心的 Borg 集群(类似于 Kubernetes)。
-
真实服务器 (Borg Pod):
-
这里跑着 Python/C++/TPU 计算逻辑。
-
关键点:这些服务器只有内网 IP(比如
10.0.0.5),根本没有公网 IP!外界通过互联网绝对无法直接连上它们。
-
3. 🚀 你的架构应该怎么改?(面试加分项)
既然你明白了原理,在面试中可以画出这样的标准安全架构图:
代码段
用户 (Browser)
│
▼
[ 🌍 Cloudflare / 阿里云 CDN ] <--- 第一层盾:隐藏源站 IP,抗 DDoS
│ (IP: 1.1.1.1)
▼
[ 🛡️ 你的 Nginx 网关 ] <--- 第二层盾:反向代理,限流,WAF
│ (IP: 81.70.x.x - 仅允许 CDN 访问)
▼
[ ☕️ Tomcat / SpringBoot ] <--- 核心业务 (被保护)
│ (IP: 127.0.0.1 或 内网 IP)
▼
[ 🛢️ MySQL / Redis ] <--- 数据核心 (完全隔离)
(仅内网访问)
面试话术总结:
“为了安全,我采用了反向代理架构。
用户首先访问 CDN 或 Nginx,Nginx 作为流量网关,负责 SSL 卸载和非法请求拦截。
而我的真实后端服务(SpringBoot)运行在内网环境或仅监听本地端口,不直接对外暴露公网 IP。
这样即使攻击者想通过 IP 直接攻击核心服务,也会因为网络不可达而失败,这不仅保护了带宽,也缩小了攻击面。”
简单说:Nginx 就是那个挡在前面的“保镖”,Tomcat 是坐在屋里数钱的“老板”。老板绝对不能亲自去大街上拉客!
你的项目用到了 Nginx 了吗,怎么配置的
你的 nginx.conf 配置非常标准,最关键的一行配置是:
Nginx
include /etc/nginx/conf.d/*.conf;
这意味着:千万不要直接改 nginx.conf 来添加你的 Java 项目配置!
最优雅、最规范的做法是:在 conf.d 目录下新建一个单独的 .conf 文件(比如叫 project.conf)。这样你的博客配置(quartz.conf)和项目配置互不干扰,以后想删哪个直接删文件就行。
🛠️ 具体操作步骤
第一步:纠正一个小错误 (解释为什么你刚才 cat 失败)
你刚才在 /etc/nginx 目录下运行 ls conf.d 看到了 quartz.conf,但是紧接着运行 cat quartz.conf 报错了。
原因:文件在文件夹里,你得带上文件夹名字。
应该输入:cat conf.d/quartz.conf 才能看到内容。
第二步:新建项目配置文件
我们要创建一个新的配置文件,专门用来反向代理你的 Java 项目(监听 8080 端口,转发给 3000)。
在终端输入:
Bash
vim /etc/nginx/conf.d/project.conf
第三步:粘贴配置代码
按 i 进入编辑模式,复制粘贴以下内容:
Nginx
server {
# 1. 对外监听 8080 端口 (这是面试官访问的入口)
listen 8080;
# 2. 你的服务器公网 IP
server_name 81.70.76.245;
# 3. 访问日志 (可选,方便排错)
access_log /var/log/nginx/project_access.log;
error_log /var/log/nginx/project_error.log;
location / {
# 4. 核心:转发给本机的 Docker 容器 (端口 3000)
proxy_pass http://127.0.0.1:3000;
# 5. 必须带的头信息 (否则后端拿不到真实 IP,日志里全是 127.0.0.1)
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 6. 支持 WebSocket (如果你的项目用到 WebSocket 必须加这三行)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}粘贴完后:
-
按
Esc键。 -
输入
:wq并回车保存。
第四步:检查并生效
一定要先检查语法,防止写错导致 Nginx 挂掉。
Bash
nginx -t
如果看到 syntax is ok 和 test is successful,由于你开启了 Gzip,可能会提示 duplicate "gzip" 警告,如果是 warn 可以忽略,只要不是 error。
然后重载配置:
Bash
nginx -s reload
🔒 第五步:最重要的一步(安全加固)
现在的状态是:
-
入口 A:
http://81.70.76.245:8080(通过 Nginx 访问,推荐) -
入口 B:
http://81.70.76.245:3000(直接捅 Docker 容器,不安全)
为了实现你说的“嵌套一层更安全”,你需要去腾讯云控制台的防火墙(安全组):
-
添加规则:允许
TCP:8080(让面试官访问)。 -
删除/禁止规则:删除
TCP:3000的规则。
做完这一步,外界就彻底无法直接接触你的 Docker 容器了,必须乖乖走 Nginx 的 8080 门禁。
配置细节?
没错,你的理解非常精准!
答案是:是的,Nginx 启动时会把所有的 .conf 文件“脑补”拼接成一个超级大的文件。
我来解释一下这背后的机制,以及“撞车”(冲突)了会发生什么。
1. 它是怎么知道“所有文件”的?
并没有什么魔法,全靠你 nginx.conf 里的这一行代码(你刚才发给我的截图里就有):
Nginx
include /etc/nginx/conf.d/*.conf;
-
include:意思是“包含/引入”。 -
*.conf:意思是“所有以 .conf 结尾的文件”。
Nginx 的启动过程是这样的:
-
读取主文件
nginx.conf。 -
读到
include这一行时,它会扫描conf.d文件夹。 -
它发现里面有
quartz.conf和project.conf。 -
它在内存里,把这俩文件的内容复制粘贴到
include所在的位置。 -
最终在内存里形成一个完整的逻辑配置树。
2. 冲突了怎么办?
Nginx 非常聪明,它有一套严格的规则来处理冲突。通常有两种情况:
情况 A:端口相同,但域名不同(这是合法的 ✅)
假设你有两个文件:
-
blog.conf: 监听 80,server_name blog.com -
shop.conf: 监听 80,server_name shop.com
Nginx 说:“没问题!虽然都是 80 端口,但我会根据用户请求的域名(Host)来判断把请求分给谁。” 这就是虚拟主机原理。
情况 B:端口相同,域名也相同(这是违法的 ❌)
假设你手滑了,在 quartz.conf 里监听了 8080,在 project.conf 里也监听了 8080,而且 server_name 都是 IP。
后果:Nginx 拒绝启动!
当你输入 nginx -t 或者重启时,它会直接报错,并告诉你哪一行冲突了。
报错示例:
Plaintext
nginx: [emerg] bind() to 0.0.0.0:8080 failed (98: Address already in use)
...
nginx: configuration file /etc/nginx/nginx.conf test failed
翻译过来就是:“紧急情况!8080 端口已经被占用了,我绑定不上!启动失败!”
3. 针对你现在的两个文件
我们来看看你现在的配置,完全不会冲突:
| 配置文件 | 监听端口 (Listen) | 域名/IP (Server Name) | 作用 | 冲突吗? |
|---|---|---|---|---|
quartz.conf | 80 | 81.70.76.245 | 博客 | No |
project.conf | 8080 | 81.70.76.245 | Java项目 | No |
结论:
因为它们的端口号不一样(一个是 80,一个是 8080),就像你家的正门和后门。
Nginx 能够轻松同时管理这两个门,完全互不干扰。
💡 这里的“防坑”小技巧
既然可以有多个文件,建议你养成好习惯:每次修改完配置,或者新增了文件,一定要先运行体检命令:
Bash
nginx -t
-
如果它说
successful,说明没有冲突,你就可以放心地nginx -s reload。 -
如果它报错,它会精确地告诉你:“duplicate … in /etc/nginx/conf.d/xxx.conf:15”(意思是:xxx.conf 的第 15 行重复定义了)。
所以,放心大胆地新建 project.conf 吧!这是最专业的管理方式。