安装

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 负责把流量分给它们。

面试加分项(必须背下来的策略):

  1. 轮询 (Round Robin):默认方式。你一个,我一个,它一个,公平分配。

  2. 权重 (Weight):服务器 A 性能强(8核),服务器 B 弱(2核)。给 A 权重设 4,B 设 1。Nginx 就会多往 A 发请求。

  3. 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 不行?”

你要回答这两个关键词:

  1. 异步非阻塞 (Event-driven)

    • Tomcat (传统模式):像“服务员一对一服务”。一个客人来,分配一个服务员(线程)一直死等他点菜、吃完。客人多了,服务员不够用,由于线程切换开销大,服务器就崩了。

    • Nginx (Epoll 模型):像“收银员”。一个收银员处理所有人的排队。你点菜慢?你去旁边想好了再来,我先给下一位结账。它不需要为每个连接创建一个线程,而是用一个进程处理成千上万个连接。

  2. Master-Worker 进程模型

    • 一个 Master(老板)负责管理配置。

    • 多个 Worker(打工人)负责真正干活。Worker 数量通常等于 CPU 核数,完全利用多核性能,没有线程切换的浪费。


🎤 总结:下次面试官问“你了解 Nginx 吗?” 该怎么说?

请背诵并根据自己的情况微调下面这段话:

“了解的。在我之前的项目(比如那个 DDD 抽奖平台或个人博客)中,Nginx 主要承担了 网关 的角色。

  1. 反向代理与动静分离:我使用 Nginx 代理前端的静态资源(HTML/CSS/JS),利用其高效的 IO 性能提升加载速度,同时将 /api 接口请求转发给后端的 SpringBoot 集群,实现动静分离。

  2. 性能优化:我配置了 Gzip 压缩,将文本类资源体积减少了 70%,有效节省了服务器带宽。同时配置了 Keep-alive 长连接,减少了 TCP 握手的开销。

  3. 架构理解:我还了解 Nginx 底层是基于 Epoll 的异步非阻塞模型Master-Worker 进程机制,这使得它在处理高并发连接时,内存占用极低且稳定性极高。

(如果还想秀):如果是集群环境,我还会配置 Upstream 实现负载均衡,通过 IP HashWeight 策略来分配流量。”

你看,这样回答,是不是比“只负责改页面”要专业 100 倍? 😎

Tomcat是什么

这是一个非常敏锐的问题!你正在触及 Web 架构的核心:分层

简单直接的回答:

  1. Tomcat 是后端服务器吗? 是的,但它更准确的名字叫 “Java 应用服务器”(或者 Servlet 容器)。它的核心职责是**“跑 Java 代码”**。

  2. 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. 它们是如何配合的? (动静分离)

这就是我们常说的架构图:

  1. 用户 (Browser) 发起请求:www.xinduan.top

  2. Nginx (80/443端口) 拦截请求:

    • 如果是 avatar.jpg(你的头像):Nginx 直接从硬盘拿给你,耗时 1ms

    • 如果是 /api/login(登录接口):Nginx 转身把请求转发给身后的 Tomcat。

  3. Tomcat (8080端口) 收到请求:

    • 启动 Java 线程,运行 Spring Boot 代码,查 MySQL 数据库,验证密码。

    • 生成结果:“登录成功”。

    • 把结果还给 Nginx。

  4. 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 为例):

  1. 用户浏览器: 输入 gemini.google.com

  2. DNS 解析: 告诉浏览器,去访问 IP 142.250.x.x(这是 Google 的 Anycast 边缘节点 IP,类似于 CDN,全球有很多个)。

  3. GFE (类 Nginx 层):

    • 边缘节点收到请求,解密 HTTPS。

    • 根据 URL /app/... 判断这是 Gemini 的业务。

    • 流量清洗:判断你是不是黑客。

  4. 内网传输 (RPC): GFE 通过 Google 极其恐怖的内网专线,把请求发给位于美国某个数据中心的 Borg 集群(类似于 Kubernetes)。

  5. 真实服务器 (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";
    }
}

粘贴完后:

  1. Esc 键。

  2. 输入 :wq 并回车保存。

第四步:检查并生效

一定要先检查语法,防止写错导致 Nginx 挂掉。

Bash

nginx -t

如果看到 syntax is oktest is successful,由于你开启了 Gzip,可能会提示 duplicate "gzip" 警告,如果是 warn 可以忽略,只要不是 error。

然后重载配置:

Bash

nginx -s reload

🔒 第五步:最重要的一步(安全加固)

现在的状态是:

  • 入口 Ahttp://81.70.76.245:8080 (通过 Nginx 访问,推荐)

  • 入口 Bhttp://81.70.76.245:3000 (直接捅 Docker 容器,不安全)

为了实现你说的“嵌套一层更安全”,你需要去腾讯云控制台的防火墙(安全组):

  1. 添加规则:允许 TCP:8080 (让面试官访问)。

  2. 删除/禁止规则:删除 TCP:3000 的规则。

做完这一步,外界就彻底无法直接接触你的 Docker 容器了,必须乖乖走 Nginx 的 8080 门禁。

配置细节?

没错,你的理解非常精准!

答案是:是的,Nginx 启动时会把所有的 .conf 文件“脑补”拼接成一个超级大的文件。

我来解释一下这背后的机制,以及“撞车”(冲突)了会发生什么。

1. 它是怎么知道“所有文件”的?

并没有什么魔法,全靠你 nginx.conf 里的这一行代码(你刚才发给我的截图里就有):

Nginx

include /etc/nginx/conf.d/*.conf;
  • include:意思是“包含/引入”。

  • *.conf:意思是“所有以 .conf 结尾的文件”。

Nginx 的启动过程是这样的:

  1. 读取主文件 nginx.conf

  2. 读到 include 这一行时,它会扫描 conf.d 文件夹。

  3. 它发现里面有 quartz.confproject.conf

  4. 它在内存里,把这俩文件的内容复制粘贴include 所在的位置。

  5. 最终在内存里形成一个完整的逻辑配置树。


2. 冲突了怎么办?

Nginx 非常聪明,它有一套严格的规则来处理冲突。通常有两种情况:

情况 A:端口相同,但域名不同(这是合法的 ✅)

假设你有两个文件:

  • blog.conf: 监听 80server_name blog.com

  • shop.conf: 监听 80server_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.conf8081.70.76.245博客No
project.conf808081.70.76.245Java项目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 吧!这是最专业的管理方式。