拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Nginx与Tomcat整合部署指南:反向代理、负载均衡与故障排查

1. 整体设计思路为什么 Nginx 和 Tomcat 非要凑在一起用1.1 两个服务的角色定位完全不同很多刚接触服务端部署的同学第一反应是“Tomcat 能跑 Java 项目Nginx 也能跑静态页面那岂不是随便用一个就行” 这是最常见的误解。Tomcat 的核心身份是 Servlet 容器它最擅长的是接收 Web 请求交给 Servlet/Spring MVC 去处理再返回动态内容而 Nginx 的核心身份是 Web 服务器和请求转发入口它最擅长的是高并发下处理静态资源、统一接收外部流量、把请求转给后端的业务服务。拿开实体店来类比比较直观Nginx 是站在门口的接待员所有客人先过它这一关它决定你该去哪个柜台Tomcat 是柜台后面的工作人员真正干活、处理业务逻辑的是它。如果让柜台工作人员直接去门口接待所有人人多时队伍就会乱成一团如果只有门口接待员而没有柜台人员那用户交办的事根本没人处理。Nginx 和 Tomcat 组合在一起本质就是把“接客”和“干活”这两件事拆开各管一段。1.2 三种常见的组合架构方案我根据这几年部署项目的经验把最常见的三套玩法整理一下你可以直接对号入座。第一种是最简单的单机单应用。服务器上装一个 Nginx、一个 TomcatNginx 监听 80 端口Tomcat 监听 8080 端口外部用户通过域名访问 NginxNginx 把所有请求原样转发给 Tomcat。这套结构适合个人博客、小型管理系统、公司内部系统部署简单排查问题也容易。第二种是动静分离。Java 项目里的静态资源图片、CSS、JS 文件不再让 Tomcat 管而是直接交给 Nginx 用location匹配资源路径从磁盘上读出来返回给浏览器。动态请求才转发到 Tomcat。这样做的好处非常明显Tomcat 不用再花线程去吐静态文件压力会小很多Nginx 处理静态资源的吞吐量比 Tomcat 高出一个量级。第三种是多实例负载均衡。后端跑两个甚至多个 Tomcat 实例Nginx 通过upstream定义一个服务器池把请求轮流分发到不同实例上。这套架构一般用在用户量起来之后目的是分摊压力同时还能做到一台 Tomcat 挂掉时 Nginx 自动把请求转发到另一台业务不中断。1.3 为什么不直接让用户访问 Tomcat有人会觉得既然 Tomcat 也能处理请求那直接让用户访问http://服务器IP:8080不就行了问题在于Tomcat 直接暴露给外部会有几个很现实的问题。第一端口不友好。Tomcat 默认端口是 8080用户访问时必须在域名后面加端口号如果一台机器上有多个 Tomcat 实例端口都不一样体验很糟。Nginx 统一占住 80 端口HTTPS 就是 443对外只需要一个地址。第二Tomcat 处理高并发静态请求的效率一般。图片、JS、CSS 这类资源即使走 Java 容器也能返回但它每处理一次请求就要消耗一个线程线程数量有限静态资源一多动态接口就被拖慢。Nginx 解决这个问题几乎不费劲它基于事件驱动模型单进程可以撑住大量并发连接。第三很多扩展能力需要统一入口。比如要做 HTTPS 证书卸载、接口限流、请求头改写、日志统一采集放在 Nginx 上比逐个改 Tomcat 实例要方便得多。你只需要在 Nginx 上改一遍配置后端多个 Tomcat 全部生效。这也是为什么企业里几乎清一色是“Nginx Tomcat”或者“Nginx 其他后端服务”这套模式。2. Nginx 安装与核心配置详解2.1 下载安装Windows 和 Linux 两种方式都要会Nginx 官方下载地址就是nginx.org的首页点download进去选稳定版本就行。有两点要提醒第一不要一看到Mainline version就去下载线上环境老老实实用Stable version第二Windows 下下载 zip 包Linux 下一般用系统自带的包管理工具安装或者源码编译安装。Linux 上如果是 CentOS/RHEL 7/8 系列最简单的方式是配置官方仓库后装rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm yum install -y nginx systemctl enable nginx systemctl start nginx如果服务器在内网环境、完全连不上外网那就走离线安装。在一台能联网的同版本机器上执行yum install --downloadonly --downloaddir/root/nginx-rpm nginx把/root/nginx-rpm目录下的 rpm 包打包拷到内网机器里再执行rpm -Uvh *.rpm。这里要特别留意依赖nginx 会依赖openssl、zlib、pcre这几个库离线打包时最好把这些依赖一起下载进去否则内网安装时会报“缺少依赖”。Windows 上更简单把 zip 包解压到磁盘比如D:\nginx-1.26.0然后打开命令行进入目录直接执行start nginx.exeNginx 就在后台跑起来了。用tasklist | findstr nginx可以确认进程是否存在或者访问本机 IP 看到 Nginx 欢迎页就说明启动成功。另外现在也有一些可视化配置工具比如nginxconfig.io网页工具可以帮你快速生成一份基础配置。新手可以用来起步但我不建议完全依赖它因为你迟早要面对线上环境手写配置的场景理解每一项配置含义比工具重要得多。2.2 nginx.conf 核心结构逐行拆解Nginx 的配置文件默认在/etc/nginx/nginx.conf源码编译安装则在安装目录conf/nginx.conf。每个人的配置五花八门但核心骨架永远是下面这几层。worker_processes auto; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server { listen 80; server_name example.com; location / { root html; index index.html; } } }worker_processes是工作进程数可以理解成 Nginx 雇了多少个服务员。auto表示按照 CPU 核数自动设置一般机器直接写 auto 就行。events块里的worker_connections是每个工作进程能同时保持的连接数上限两个数乘起来大致就是 Nginx 单机支持的并发连接数。http块是整个配置的主体里面最核心的是server块。一个server就相当于一个“虚拟主机”可以有不同的listen端口和server_name域名互不干扰。listen 80表示监听 80 端口server_name填你的域名或者下划线_表示匹配所有域名。location块是匹配请求路径的规则我不止一次见过有人在这里栽跟头。location /会匹配所有路径location /api/只匹配以/api/开头的路径。需要注意的是location匹配路径时不带主机名只匹配 URI 部分所以写的时候不要写成location example.com/api/。修改完配置后一定要先执行nginx -t检查语法它会提示配置文件第几行有问题。确认没错后再执行nginx -s reload重新加载配置这个操作不会中断现有连接是生产环境里最标准的更新方式。2.3 端口号修改和启动参数避坑Windows 或者服务器上要修改 Nginx 端口时很多人习惯把配置里的listen 80改成listen 8088就完事。但你要知道如果一台机器上同时跑了 Tomcat 占用 8080Nginx 再想听 8088端口本身不冲突可是你需要去防火墙里把这个新端口放行。Windows 上比较容易忽视这一点排查半天配置没问题其实请求根本没过防火墙。我见过一些线上事故同事把listen 80改成listen 8088后访问域名测试结果直接 404因为 Nginx 收到的是 80 端口的请求配置却在 8088 上等。改端口之前先在系统里确认监听情况netstat -lntp | grep 80 # Linux netstat -ano | findstr :80 # Windows确认端口没被占用后再改。另外Windows 上nginx.exe -t可以检查配置nginx.exe -s reload可以重载nginx.exe -s stop是快速停止。注意在 Windows 上不要直接双击 nginx.exe 去刷新配置命令行操作才是标准姿势。2.4 Nginx 日志配置别等出问题才想起来Nginx 的日志分成两种访问日志和错误日志。访问日志记录每一个请求的 IP、时间、路径、状态码、UA 等信息错误日志主要记录进程启动失败、配置文件错误、5xx 状态码产生时的异常信息。默认配置下日志会写到 Nginx 日志目录的access.log和error.log。排查问题时最常用的命令就是实时盯日志tail -f /var/log/nginx/access.log tail -f /var/log/nginx/error.log在对接 Tomcat 时如果用户访问返回 502 但 Nginx 没报错就看 access.log 里对应的状态码如果怀疑后端 Tomcat 有问题就去翻 Tomcat 的日志。两边日志结合起来比对基本能定位 90% 的问题。日志格式如果默认不好看可以在 http 块里自定义log_format但新手阶段先不用深究先学会在出问题时知道去哪里看日志就成功了一半。3. Tomcat 安装、部署与启动问题排查3.1 Tomcat 版本选择和安装前必须检查的事Tomcat 官网下载地址是tomcat.apache.org。进去之后会看到很多版本8.5、9.0、10.1、11.0 等等。选版本时不是越新越好关键要看你的项目用的 Java 版本和 Servlet 规范。简单对应关系是这样的Tomcat 9.0 对应 Java 8 及以上支持 Servlet 4.0Tomcat 10.1 对应 Java 11 及以上支持 Servlet 5.0/6.0。如果你的项目还是老的 JSP/Servlet 代码并且用的是 Java 8老老实实选 Tomcat 9.0 最稳妥。安装 Tomcat 没什么技术含量Linux 上解压 tar.gz 包就行tar zxvf apache-tomcat-9.0.98.tar.gz mv apache-tomcat-9.0.98 /usr/local/tomcat /usr/local/tomcat/bin/startup.sh启动前必须先把 Java 环境配置好。Tomcat 本身是 Java 程序没有 JRE/JDK 它根本跑不起来。Linux 上验证java -version能正常输出版本Windows 上检查JAVA_HOME环境变量有没有指到 JDK 目录。启动后如果想确认是不是真的启动了用ps -ef | grep tomcat看进程是最直接的。我自己习惯在启动脚本里连着执行一遍先 ps 看一下有没有进程再 curl 一下本机 8080 端口ps -ef | grep tomcat curl -I http://127.0.0.1:8080如果返回 HTTP 状态码 200说明 Tomcat 已经在正常监听请求了。这时候再用浏览器访问服务器公网 IP:8080能看到 Tomcat 默认首页。3.2 Tomcat 目录结构学会之后部署 war 包就不慌解压后的 Tomcat 目录内容很多但日常打交道的就那么几个。bin存放启动和停止脚本startup.sh、shutdown.shWindows 下是.bat文件。conf核心配置文件目录最重要的server.xml在这里。webapps部署目录war 包丢进去就会自动解压部署。logs日志目录Java 项目打出的日志和 Tomcat 自身日志都会落在这里。workJSP 编译后的临时文件目录部署新版本时偶尔需要清理。部署 Java Web 项目时最常见的方式就是直接把xxx.war文件扔进webapps然后启动 Tomcat 或者等它自动解压。比如你把一个blog.war放进去Tomcat 启动后会出现一个blog目录访问路径就是http://IP:8080/blog/。如果想直接用根路径访问把 war 包改名为ROOT.war或者把解压出来的内容放到webapps/ROOT目录下。一些同学习惯用 IDEA 或者 Eclipse 集成 Tomcat 调试。IDEA 里需要先配置 JDK再在运行配置里添加 Tomcat Server指定 Tomcat 安装目录然后就可以点击运行按钮把项目部署进去。社区版 IDEA 也能配只是少了企业版的一些快速部署按钮手动添加 Tomcat 的逻辑是一样的。不过要记住IDE 里跑的 Tomcat 不会受到webapps目录里手工放置的 war 包影响它用的是专门的部署目录。3.3 server.xml 端口配置细节Tomcat 的server.xml里有三个端口最容易让人混淆。Server port8005 shutdownSHUTDOWN Connector port8080 protocolHTTP/1.1 connectionTimeout20000 redirectPort8443/ Connector port8009 protocolAJP/1.3 redirectPort8443/8005 是管理端口用于接收关闭命令的。如果有人把shutdownSHUTDOWN改掉shutdown.sh会失效。8080 是 HTTP 访问端口用户通过浏览器访问的就是这个端口。8009 是 AJP 端口一般配合 Apache HTTP Server 使用现在用的人越来越少但默认是开着的。实际部署时最常见的需求就是一台机器上跑多个 Tomcat 实例这时候必须把每个实例的 8005、8080、8009 全部改成不重复的端口。比如第一个实例用 8080第二个实例用 8081。改完之后启动第二个实例判断是否成功还是用ps -ef | grep tomcat加curl http://127.0.0.1:8081双重验证。3.4 Tomcat 启动一闪而过到底上哪看错误Windows 下双击startup.bat时经常出现一个黑窗口一闪就没了很多新手会以为“没启动成功”其实是“启动失败后窗口自动关闭了”。这时候不要慌命令行里执行catalina.bat run它会以前台模式运行错误信息会直接打印在窗口里比双击脚本好用一百倍。常见的原因通常有以下几种JAVA_HOME环境变量没配置或者指向的 JDK 路径不对。JDK 位数和 Tomcat 位数不匹配Tomcat 32 位版本配了 64 位 JDK偶尔会有兼容问题。8080 端口已经被其他程序占用Tomcat 绑定端口失败。server.xml配置写错了导致连接器初始化失败。Linux 下也可以前台启动看日志直接执行/usr/local/tomcat/bin/catalina.sh run日志会实时输出。而生产环境一般用什么方式启动后台启动用startup.sh但日志还是会写到logs/catalina.out里。排查问题时用tail -f /usr/local/tomcat/logs/catalina.out盯着看比盲目重启有效得多。3.5 访问 Tomcat 返回 404 的排查思路Tomcat 启动没问题但浏览器访问项目路径时返回 404这是部署新手问得最多的问题之一。我总结一下自己的排查顺序。第一步先确认 Tomcat 启动后logs目录下有没有生成localhost_access_log之类的访问日志。如果有说明请求确实打到了 Tomcat如果没有说明请求压根没到 Tomcat这时问题出在 Nginx 转发或者端口上。第二步确认项目是否真的部署进去了。执行ls /usr/local/tomcat/webapps看看有没有你的项目目录或 war 包。有些同事把 war 包复制到webapps后Tomcat 还没完成解压就去访问自然 404。等几秒再看一次就行。第三步确认访问路径大小写和 context path 对不对。Tomcat 的访问路径是http://IP:端口/项目目录名/严格区分大小写。最常见的坑是 URL 里少写了项目名或者项目名大小写不对。第四步看logs/catalina.out里有没有部署异常。有些项目缺少依赖war 包解压失败也会出现 404。这类问题看日志马上就能发现异常栈比瞎猜快得多。4. Nginx 与 Tomcat 对接转发配置、负载均衡和多项目部署4.1 最简单的请求转发配置当 Nginx 和 Tomcat 都装好之后接下来要做的事情就是让 Nginx 把请求转给 Tomcat。在 Nginx 的server块里新增一个 location内容如下server { listen 80; server_name _; location / { proxy_pass http://127.0.0.1:8080; 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_pass http://127.0.0.1:8080;的意思是把匹配到的请求原样转发给本机 8080 端口的 Tomcat。这里有个特别容易出错的细节proxy_pass后面带的 URI 是有讲究的。如果proxy_pass后面只有一个http://127.0.0.1:8080不带斜杠和路径Nginx 会把完整的原始 URI 直接转发给后端如果写成http://127.0.0.1:8080/或者带了子路径Nginx 就会把 location 匹配到的部分替换掉。举个实际例子。location /api/下配置proxy_pass http://127.0.0.1:8080;浏览器请求/api/user/list后端 Tomcat 收到的还是/api/user/list。如果配置成proxy_pass http://127.0.0.1:8080/;那后端收到的是/user/list前缀/api被去掉了。后端接口里如果没有/api前缀这个配置反而正常如果有就立刻 404。所以项目里接口路径带不带前缀一定要先和后端确认清楚。proxy_set_header这几行不是可配可不配的。后端项目取客户端真实 IP 时通常依赖X-Real-IP和X-Forwarded-For这两个请求头如果把四级代理链后面的 IP 全丢掉后端做日志、做风控、做统计时拿到的全是 Nginx 的 IP数据直接没法用。而Host $host是为了在转发时保留用户访问时输入的域名好多 Java 项目生成链接、跳转地址时依赖于它。4.2 upstream 负载均衡配置其实没你想的那么神秘当单台 Tomcat 扛不住流量时就需要加实例。先准备两个 Tomcat一个监听 8080一个监听 8081。然后 Nginx 配置一个upstream池子upstream tomcat_pool { server 127.0.0.1:8080 weight1; server 127.0.0.1:8081 weight2; keepalive 32; } server { listen 80; server_name _; location / { proxy_pass http://tomcat_pool; proxy_http_version 1.1; proxy_set_header Connection ; proxy_set_header Host $host; } }upstream块定义了一组后端服务器默认按照轮询方式把请求平均分发到每个服务器上。weight2表示第二台机器收到的请求数量是第一台的两倍适合后端性能不对称的场景。keepalive 32是开启 Nginx 到后端的长连接减少频繁建立 TCP 连接的开销。如果项目使用了 Session 保存登录状态负载均衡默认的轮询会导致用户第一次请求在 8080第二次请求跑到 8081Session 对不上用户就会莫名其妙地掉线。解决方式有三种一是把upstream里的调度算法改成ip_hash让同一个 IP 的请求永远进同一台 Tomcat二是在 Tomcat 之间配置 Session 共享三是项目改造为无状态登录JWT。我个人的建议是如果你的项目短期不打算做大的改造先上ip_hash最省事。负载均衡还有一个隐性价值是故障转移。当其中一台 Tomcat 挂掉时Nginx 会检测到连接失败自动把请求转发到健康的那一台用户几乎无感知。不过这要求你的应用是“多实例无状态”的不然某个实例上的本地文件、Session 数据还是会出问题。4.3 一个 Nginx 部署多个 Web 项目一台服务器上跑多个项目在 Nginx 里有两种主流方式按域名区分或者按路径区分。按域名区分是指每个项目配一个独立的server块不同的server_name对应不同的 Tomcat 实例或端口server { listen 80; server_name blog.example.com; location / { proxy_pass http://127.0.0.1:8081; } } server { listen 80; server_name shop.example.com; location / { proxy_pass http://127.0.0.1:8082; } }这是最清晰的方案用户访问什么域名Nginx 就把请求交给对应的后端服务互不干扰。按路径区分则是同一个域名下通过 location 区分不同前缀server { listen 80; server_name www.example.com; location /blog/ { proxy_pass http://127.0.0.1:8081; } location /shop/ { proxy_pass http://127.0.0.1:8082; } }如果 Tomcat 后端项目里统一带了/blog和/shop的 context path那配置就比较顺利。但如果后端项目没有这个前缀你就需要结合刚才说的proxy_pass替换规则把前缀在后面去掉。这就是很多人配完多项目后找不到页面的根本原因。另外纯前端项目比如 Vue 打包出来的 dist 目录经常直接挂在 Nginx 上不需要经过 Tomcat。常见配置是server { listen 80; server_name admin.example.com; root /data/www/admin; index index.html; location / { try_files $uri $uri/ /index.html; } }try_files $uri $uri/ /index.html;这句是前端单页应用部署的关键。Vue 通常使用 HTML5 History 路由刷新/user/list这个地址时Nginx 找不到对应的物理文件就会自动回退到/index.html然后由前端的 JS 路由接管页面。没有这行配置刷新页面就会得到 404。这个坑我踩过不止一次每次看到前端同事对着刷新后的白屏抓狂十有八九是这里。4.4 动静分离配置让 Tomcat 只管动态接口静态资源访问量大的项目建议配置动静分离。以 Spring Boot 前端资源分离为例假设后端接口都带/api前缀静态资源都在项目根的/static目录下location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location /static/ { root /data/project; expires 7d; }location /static/这个配置表示.css、.js、图片这类静态资源由 Nginx 直接从/data/project/static/目录读取并返回不会转发到 Tomcat。expires 7d则告诉浏览器这些资源可以缓存七天第二次访问速度会快不少。这里需要特别说明root和alias的区别这也是配置里比较难理解的点。root会把 location 的 URI 拼接到 root 目录后面而alias则是直接把 location 替换成 alias 指定的目录。举个例子请求/static/img/logo.png用root /data/project;找的是/data/project/static/img/logo.png用alias /data/img/;找的是/data/img/logo.png很多人在配置静态资源时本来想用 alias 却写成了 root导致 Nginx 去错误路径下找文件返回 404。这个细节必须刻在脑子里。4.5 国产化中间件替换 Tomcat 的一点思路这些年不少项目要求用国产中间件替代 Tomcat比如宝兰德 BES WebServer。初始化这类替换时很多人心里没底其实从部署角度看没那么复杂。BES WebServer 本身也是一个 Servlet 容器war 包部署方式与 Tomcat 几乎同构都是“中间件安装目录 webapps 部署目录 启动脚本”。你只需要把测试用的 war 包丢进webapps启动服务后它会在配置好的端口上监听 HTTP 请求。最需要注意的是端口配置位置变了server.xml 之类的文件名和标签有差异但总体的“Nginx 只转发到后端端口”的思路完全不受影响。也就是说Nginx 配置文件往往可以原封不动地继续使用因为它只认端口不认中间件品牌。5. 高频故障排查实录与避坑清单5.1 故障速查表看到现象直接对号入座我把这几年在 Nginx 和 Tomcat 对接中踩过的高频故障整理成了表格遇到问题可以直接查表。现象可能原因建议操作Nginx 返回 404location 路径匹配不到文件或 root/alias 写错检查 nginx.conf 对应 location确认实际文件路径Nginx 返回 502 Bad Gateway后端 Tomcat 没启动或 proxy_pass 指向的端口错误ps -ef | grep tomcatcurl http://127.0.0.1:8080验证后端Nginx 返回 504 Gateway Timeout后端接口处理时间过长超过proxy_read_timeout调大proxy_read_timeout同时排查后端慢查询刷新前端页面就 404前端是 History 路由Nginx 没有 fallbacklocation 里配置try_files $uri $uri/ /index.html;页面能打开但 JS/CSS 加载失败静态资源路径或 root/alias 配置错误浏览器 F12 看资源请求定位对应 location登录后跳转立刻掉线多个 Tomcat 实例 Session 不同步upstream 开启ip_hash或改造为无状态登录修改配置后不生效没执行 reload或浏览器缓存nginx -t后nginx -s reload并强制刷新浏览器Tomcat 启动一闪就消失JAVA_HOME 未配端口占用JDK 位数不匹配catalina.bat run前台启动看具体报错访问项目返回 Tomcat 自带的 404 页面context path 不对或 war 没部署成功检查webapps目录确认 URL 中包含正确的项目名后端日志拿不到客户端真实 IPNginx 转发时没有带上X-Forwarded-For确认proxy_set_header配置是否完整5.2 一套标准排查顺序别一上来就重启遇到问题最忌讳的就是不分析原因直接重启服务。我自己的排查顺序是固定的效率很高。先看服务进程是否存在。Linux 上用ps -ef | grep nginx和ps -ef | grep tomcatWindows 上用tasklist | findstr nginx。进程不存在直接看启动日志服务一般是被配置错误或者端口冲突干掉了。再看端口监听状态。Nginx 是否监听 80Tomcat 是否监听 8080用netstat或ss -lntp检查。这里有个细节不要只看进程在还要看端口在。进程没崩但端口没起来的情况也挺常见比如 Tomcat 配置了错误的端口号进程活着但没人在正确端口上接客。然后在本机直接测后端。curl -I http://127.0.0.1:8080如果后端正常返回说明问题一定出在 Nginx 配置上如果后端都不通先去处理 Tomcat。这样就把排查范围缩小了一半。接着检查 Nginx 配置语法。nginx -t不通过的话会有明确提示比如缺少分号、大括号没闭合、upstream 名字拼错了。重点注意proxy_pass后面的 URL 如果带/它会直接改变转发路径这是 80% 转发不对的根源。最后再看日志。Nginx 的error.log里如果有connect() failed (111: Connection refused)说明 Nginx 想连后端但连不上Tomcat 的catalina.out里如果有异常堆栈直接按照堆栈去搜解决方案。日志看明白了问题基本也就定位了。5.3 配置了却不生效多问自己三个问题“我明明配置了为什么没生效”这个问题我几乎每个月都能在团队里听到一次。每次我都会反问三个问题。第一你改的是不是 Nginx 实际加载的那个配置文件Linux 下 Nginx 主配置如果是/etc/nginx/nginx.conf里面可能有include /etc/nginx/conf.d/*.conf;这样的写法。有些同事改了/etc/nginx/nginx.conf但实际生效的 server 块在/etc/nginx/conf.d/default.conf里改错了文件自然改了没用。用nginx -T可以打印出所有生效配置一眼就能看出真正加载了哪些文件。第二你改完配置后是 reload 还是 restart如果是修改了listen、server_name这类监听参数reload 一般没问题但如果是修改了 Nginx 的用户权限、线程数这类全局参数reload 偶尔不够需要 restart。生产环境我不建议随便 restart因为会造成短暂断连优先用nginx -s reload。第三浏览器里的缓存是不是害你白忙活有些前端改动明明 Nginx 和 Tomcat 都验证过没问题浏览器访问还是旧页面。这不是服务器问题是浏览器缓存或者 CDN 缓存。打开无痕窗口试一下或者给静态资源加版本号参数比如app.js?v20250101。5.4 权限、防火墙和环境变量这些隐性问题服务器上部署时还有个经常被忽略的干扰项SELinux 和防火墙。CentOS 环境里即使端口监听正常、Nginx 配置正确外部访问仍然失败很多时候就是 SELinux 开着限制了 Nginx 的网络访问。临时验证方式setenforce 0如果关了 SELinux 后访问正常说明确实是它的问题。生产环境不建议直接关闭用chcon调整目录上下文或者写对应的 SELinux 模块才是正道但新手可以先通过临时关闭来验证方向。防火墙也要排队确认。CentOS 7 以上默认是 firewalld查看 80、8080 是否放行firewall-cmd --list-all firewall-cmd --permanent --add-port80/tcp firewall-cmd --reloadWindows Server 上部署 Nginx 和 Tomcat 时也要检查 Windows 防火墙的入站规则。特别是 Windows Server 2016 这类系统默认防火墙会拦截非常规端口只放行 80 和 443 远远不够Tomcat 监听的 8080 如果不放行Nginx 转发到后端也会失败。环境变量这块要单独提一句。Tomcat 需要 JAVA_HOME但很多人装完 JDK 后忘了配置环境变量Linux 下用export JAVA_HOME/usr/local/jdk临时指定可以启动但每次重启都会失效最好写进/etc/profile里。Windows 下配置完环境变量后一定要重新打开命令行窗口旧窗口里配置不会刷新这点很坑。5.5 多实例部署时的几个经典坑一台机器跑多个 Tomcat 时坑比单实例多不少。第一个坑是多个实例共用了同一个webapps目录或者logs目录。如果复制 Tomcat 目录时没有彻底改干净两个实例写同一个日志文件日志会互相覆盖排查问题时看到的可能是另一个实例的输出。标准做法是每个 Tomcat 实例独享一份完整目录端口不同、目录不同、日志独立。第二个坑是bin目录下的启动脚本没有区分实例。如果直接用/usr/local/tomcat1/bin/startup.sh和/usr/local/tomcat2/bin/startup.sh依次启动会发现实际上是同一套配置跑了两遍第二遍因为端口占用直接失败。启动前先确认server.xml里的三个端口都不同再执行启动。第三个坑是 Nginx 负载均衡配置里的upstream名字写错。proxy_pass http://tomcat_pool;后面的名字必须和upstream tomcat_pool {}完全一致大小写也算。写错后nginx -t会直接报错所以语法检查一定要养成习惯。第四个坑是后端项目里的绝对路径。项目里有文件上传、模板渲染时经常会在 Java 代码里写死一个路径比如/usr/local/tomcat/webapps/upload。一旦部署到第二个实例路径不对上传功能就废了。正确的做法是把文件存储目录通过配置中心或者环境变量抽离出来不要依赖 Tomcat 的安装目录。最后再分享一个小习惯说了这么多配置和排查其实我个人最深的一个体会是所有的“玄学问题”最后都能落到日志上。只要 Nginx 的 access.log、error.log 和 Tomcat 的 catalina.out 三个日志都打开出问题时从请求到达 Nginx 那一刻开始往后追一步对一步绝对能找到问题点。我见过太多同事一遇到 502 就去重启服务结果重启十次还是老样子其实只要看一眼 Nginx error.log 里那句connect() failed立刻就知道该去看 Tomcat 进程或是端口了。另一个伴随我很长时间的小习惯是每改一次 Nginx 配置都要执行一次nginx -t不管改动多小。语法检查通过是底线任何跳过这个动作的行为都是在给自己埋雷。配置文件的备份我也建议做一下GIt 里维护一份nginx.conf的版本记录出问题时回滚只是分分钟的事。服务配置这件事本质上就是用规则把流量管好规则清晰、日志在手再复杂的架构也不会让人手足无措。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门