把本地辛辛苦苦写的Spring Boot项目打成jar包,兴冲冲传到Windows服务器上,双击运行,结果要么启动失败,要么自己电脑能访问、同事访问不了,要么外网根本打不开。这个场景我见过太多回了,自己早期也被折腾得够呛。这篇博文把整个流程从头到尾捋一遍:环境准备、jar包打包、Windows服务器部署、开机自启、外网访问配置,以及各种坑的排查方法,全部记录下来,照着操作就能搞定。
这套内容主要面向两类人:一类是刚入门Java开发、第一次独立部署项目的朋友;另一类是手里有个人项目或小系统,想挂在Windows服务器上给外部访问的开发者。整个过程不涉及复杂的集群和容器编排,就是最朴实的一套单机部署方案,但胜在完整、能落地。
1. 部署思路梳理:搞清“外网可访问”的本质
很多新手第一次部署时,最容易犯的错是一上来就打包、上传,结果卡在“外网访问”这一步进退两难。其实整件事拆开看,就三个核心问题:jar包怎么在Windows上稳定跑起来、怎么让服务随开机自启不用手动管、怎么把服务器上的端口暴露到外网。
1.1 部署目标的拆解:从“能跑”到“能访问”要过四关
我用一个最典型的场景来说明:你有个Spring Boot项目,本地跑得好好的,用的8080端口。现在要把它放到一台Windows Server 2019或Windows 10/11的机器上,目标是让不在同一局域网的人也能访问。
要达成这个目标,至少过四关:
- 第一关,环境关。服务器上得有JRE或JDK,且版本要和项目编译版本匹配。很多启动即失败的问题,根源就是JDK版本不对。
- 第二关,打包关。本地项目要打成一个“可执行jar包”,依赖要打进去,配置文件要能外置。这个环节常见错误是打出来的包只有几十KB,因为Spring Boot的repackage没生效。
- 第三关,守护关。直接用
java -jar启动,一旦关了黑窗口,服务就没了;服务器重启,服务也没了。所以要写成Windows服务,或者用脚本做守护。 - 第四关,网络关。服务在服务器本机跑起来了,但外网访问还牵扯到Windows防火墙、路由器/云安全组、以及你是否需要公网IP或内网穿透。
这四个关卡看似独立,但它们的顺序不能乱。先把本地跑通,再上服务器,最后再做网络。我见过太多人先把防火墙关了、把内网穿透配好了,结果jar包都没跑起来,然后左右排查发现根本没监听端口,浪费时间。
1.2 外网访问的三条路:公网IP、端口映射、内网穿透
“外网可访问”这件事,本质上就是让别人通过一个公网地址找到你这台服务器,再通过端口找到你的Java进程。具体路径有下面三种,选择哪个取决于你有没有公网IP,以及你的服务器部署在哪里。
| 方案 | 前提条件 | 成本 | 适用场景 | 稳定性 |
|---|---|---|---|---|
| 方案一:服务器直接绑公网IP + 放行端口 | 有公网IP的云服务器或独享IP机房 | 中(服务器月租) | 正规项目、企业应用 | 最高 |
| 方案二:路由器端口映射(NAT转发) | 家里/公司宽带 + 光猫能改桥接 + 有公网IP | 低(电费+宽带费) | 个人项目、临时演示 | 中(依赖运营商) |
| 方案三:内网穿透工具(如cpolar、花生壳) | 无需公网IP,工具装在Windows上即可 | 低(免费额度或几十块/月) | 个人项目、演示、外出访问 | 中(依赖第三方服务) |
我在实际部署中最常用的是方案一和方案三。方案二看着省事,但国内很多宽带运营商默认不分配公网IPv4,就算路由器配了端口映射,外网也访问不到你的内网地址,需要先确认你宽带是不是真的拿到了公网IP。判断方法很简单:看路由器WAN口IP是不是一个公网地址(比如183.x.x.x、120.x.x.x这种),如果路由器里显示的WAN口IP是192.168.x.x、100.64.x.x这种,基本可以断定是大内网,端口映射这条路走不通。
所以,本博文的主干内容会按“先在服务器上把jar包跑起来,再按你的网络条件选择外网路径”这个顺序来写,这是最稳妥的部署节奏。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 部署开始前的环境准备:JDK、Maven和项目打包
这一步看着基础,却是整个部署过程中返工率最高的环节。很多人在本地用IDEA启动项目没问题,但打包出来放到服务器上一运行就报错,十有八九是环境版本不匹配,或者打包方式有问题。
2.1 JDK安装与环境变量配置:版本选择有讲究
Windows服务器上安装JDK,我建议装JDK 8或JDK 11,除非你的项目用了比较新的语法特性,否则JDK 8依然是目前兼容性最好的选择,尤其是一些老项目依赖的第三方库,在JDK 17上反而会有一堆反射相关的报错。JDK 8对应Java 8,JDK 11对应Java 11,两者在API上差异不大,但运行时行为有区别,务必和本地开发版本保持一致。
安装步骤比较简单,但有几个点要注意:
- 下载JDK安装包(当前推荐jdk-8u202或更高版本,也可以下载JDK 11 LTS),双击安装到统一目录,比如
C:\Java\jdk1.8.0_202。 - 配置环境变量。右键“此电脑” → “属性” → “高级系统设置” → “环境变量”。在“系统变量”里新建
JAVA_HOME,变量值填你的JDK安装路径,比如C:\Java\jdk1.8.0_202。然后编辑Path变量,在开头加上%JAVA_HOME%\bin。 - 验证安装。打开新的cmd窗口,执行
java -version,能正常输出版本信息就说明安装成功。注意,配好环境变量后要新开窗口才生效。
提示:不要把JDK安装在带空格的目录里(比如
C:\Program Files\Java),虽然现代工具链一般能处理,但有些老脚本、批处理在解析路径时会被空格搞崩。统一放在C:\Java下最省心。
2.2 Maven安装与配置:打包前的必要准备
Maven是Java项目的构建工具,Spring Boot项目的jar包就是通过Maven打出来的。在服务器上当然不需要装Maven,但我在本地开发机上装了,因为需要用它来编译打包。如果你在本机用IDEA的Maven插件,也可以在IDEA里直接打jar包,但命令行操作更可控,也方便写脚本自动化。
Maven安装也很简单:
- 从Apache官网下载Maven二进制zip包,解压到
D:\apache-maven-3.8.8(版本号随意,3.8.x或3.9.x均可)。 - 配置环境变量
MAVEN_HOME指向解压目录,Path里加%MAVEN_HOME%\bin。 - 修改
conf\settings.xml,把本地仓库路径换到非系统盘,比如<localRepository>D:\maven-repo</localRepository>。这一步不是必须的,但我强烈建议做,因为你后续项目越来越多,本地仓库会膨胀到几个GB,放在C盘会被系统盘空间折磨疯。 - 验证:新开cmd执行
mvn -v,能看到版本信息就OK。
2.3 打包jar包:mvn clean package和repackage的区别
打包这一步是新手最容易踩坑的地方。如果你在IDEA右侧Maven工具栏点package,或者在命令行执行mvn clean package -DskipTests,打完包后去target目录看,会发现有两个jar文件:
xxx-0.0.1-SNAPSHOT.jar—— 这个才是Spring Boot的可执行jar包,通常有几MB到几十MB,内部包含依赖的第三方库。xxx-0.0.1-SNAPSHOT.jar.original—— 这是Maven默认打的普通jar包,只有项目代码,没打依赖,通常只有几百KB。
如果你的target目录里只有一个几百KB的jar包,没有大体积的jar,说明Spring Boot Maven插件没有生效。在pom.xml里必须有这样一段配置:
xml复制<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
这个插件的作用就是做“repackage”,把普通jar包重新整理成内嵌依赖的可执行jar。所以打包前检查一下pom里有没有这段。我帮别人排查过一次:项目里只有.mvn目录,没有父pom的插件管理,打包出来就是不可执行的jar,启动一直报“no main manifest attribute”。
打包时的几个实用选项:
- 跳过测试:
mvn clean package -DskipTests,测试代码有坑就不让它阻塞打包。 - 指定Profile:如果你的项目有
application-dev.yml和application-prod.yml,用mvn clean package -DskipTests -Pprod指定激活的profile。
打完包后,本地先把jar跑一下试试。切到target目录,执行:
bash复制java -jar xxx-0.0.1-SNAPSHOT.jar
如果报端口被占用,就是本地有程序占用了8080端口,可以先改配置或换端口。本地能跑起来,再进下一步上服务器。
3. 把jar包部署到Windows服务器:目录规划与启动脚本
服务器和本地项目能跑是两回事。到了服务器上,你要考虑的不只是“能启动”,还有“怎么方便地管理日志”“怎么重新部署”“怎么开机自启”。这一步做得好不好,直接影响你后续维护的幸福感。
3.1 服务器上的目录结构:别把所有文件堆在桌面
我见过有人直接把jar包扔在桌面上启动,然后桌面图标乱到没法看,日志文件也堆得到处都是。这里分享一个我自己用了很久的目录规划:
code复制D:\app\my-project\
├── app.jar # 可执行jar包
├── config\ # 放置外部配置文件
│ └── application-prod.yml
├── logs\ # 日志目录
│ └── my-project.log
├── start.bat # 启动脚本
├── stop.bat # 停止脚本
└── status.bat # 查看运行状态脚本
这样的好处是:jar包升级时,直接覆盖app.jar,配置文件不动,日志目录独立,方便做日志清理和归档。用D:\app而不是C盘的原因,是为了避免系统盘满了导致服务器出现各种诡异问题。
3.2 配置文件外置:改配置不用重新打包
Spring Boot的配置默认打进了jar包里的application.yml,但支持外部配置文件覆盖。规则是:项目运行目录下的config子目录、项目运行目录、classpath下的config目录,按优先级从高到低,也就是说,如果你在D:\app\my-project\config\application-prod.yml里配置了端口和数据库地址,它会覆盖jar包内部的配置。
这个特性非常实用。你的jar包可以保持“一份通用配置”,而不同服务器的差异化配置(数据库IP、端口、密钥)放在外面。后续如果服务器IP变了,只需要改外部配置文件,不用重新打包。
具体做法:在application.yml里设置spring.profiles.active=prod,或者启动时通过--spring.profiles.active=prod指定。然后外部配置文件命名为application-prod.yml放在上面说的config目录。
3.3 编写start.bat启动脚本:固化JVM参数和激活配置
在Windows上,最直接的启动方式是cmd窗口执行java -jar,但这样有几个问题:关窗口服务就停、JVM参数没法固定、启动后没法自动写日志。所以我一般会写一个start.bat,把启动命令固化下来。
一个我实际在用的启动脚本demo:
bat复制@echo off
cd /d D:\app\my-project
REM 设置JVM参数,-Xms和-Xmx设为相同,避免内存抖动
set JAVA_OPTS=-Xms512m -Xmx512m -Dfile.encoding=UTF-8
REM 激活生产环境配置,日志输出到logs目录
javaw -jar app.jar --spring.profiles.active=prod %JAVA_OPTS% >> logs\my-project.log 2>&1
echo 项目启动中,请查看日志 logs\my-project.log
pause
注意几个细节:
- 用了
javaw而不是java,这样启动时不会一直占着一个黑色cmd窗口。但配合日志重定向,你依然能在日志文件里看到启动信息。 -Xms和-Xmx设为相同,这个做法业界常见,就是为了避免JVM运行时动态扩容、缩容带来的性能开销。至于大小,看服务器内存和项目实际负载,一般256m到4g不等。如果项目是轻量接口服务,512m足够;如果要做大量内存操作,自己评估。-Dfile.encoding=UTF-8,这句话救了我很多次。Windows系统默认编码是GBK,而你的项目日志里可能用了UTF-8的中文,不设置的话日志乱码,配置文件的中文注释也会出问题。2>&1把错误输出也重定向到同一个日志,排错时不用同时看两个文件。
3.4 做成Windows服务:用NSSM实现开机自启和异常重启
start.bat只能手动启动项目,如果服务器重启了,你还得手动双击一次。这不是正式环境该有的状态。我推荐用NSSM(Non-Sucking Service Manager)把jar包注册成Windows服务,实现开机自启、服务崩溃自动重启、统一用Windows服务管理器控制。
NSSM是一个单文件exe工具,下载后放在D:\tools\nssm\nssm.exe。注册服务的步骤如下:
- 以管理员身份打开cmd,切到NSSM所在目录。
- 执行
nssm install MyProjectService,会弹出一个图形化配置窗口。 - 在“Application”页签里,Path填
javaw.exe的完整路径(比如C:\Java\jdk1.8.0_202\bin\javaw.exe),Startup directory填D:\app\my-project,Arguments填-Xms512m -Xmx512m -jar app.jar --spring.profiles.active=prod。 - 切到“Log on”页签,可以选择让服务以本地系统账户运行,也可以指定一个专门的服务账户。一般用Local System账户就够。
- 点“Install service”完成安装。
之后就可以在services.msc里看到这个服务,右键“启动”,设置启动类型为“自动”。以后服务器重启,服务会自动拉起,项目进程挂了,NSSM也会按配置自动重启。
如果不想用NSSM的图形界面,也可以用命令行直接注册:
bat复制nssm install MyProjectService "C:\Java\jdk1.8.0_202\bin\javaw.exe" "-Xms512m -Xmx512m -jar app.jar --spring.profiles.active=prod"
nssm set MyProjectService AppDirectory D:\app\my-project
nssm start MyProjectService
NSSM会记录标准输出和错误输出到它自己的日志目录,但因为我们重定向到了logs目录,NSSM里不会存太多东西,集中看一个日志文件更清晰。实测下来,NSSM跑Spring Boot服务非常稳定,比把启动脚本塞进“任务计划程序”靠谱得多。
3.5 重新部署的流程:替换jar包三步走
项目迭代后要更新线上版本,这个过程也要规范。我总结了一个三步走的流程:
- 停服务:
nssm stop MyProjectService,或者执行net stop MyProjectService。 - 替换jar包:把新的
app.jar覆盖到D:\app\my-project\app.jar。建议先备份旧的,比如copy app.jar app.jar.bak_20250601。 - 启服务:
nssm start MyProjectService,然后看日志确认启动成功。
注意:如果项目正在运行,直接覆盖jar包大概率会失败,报“文件被占用”,因为Windows下运行中的文件不能被覆盖。所以一定要先停服务再替换。如果替换后启动报错,第一时间翻日志,确认是不是新版本本身有问题,快速回滚到备份版本。
4. 外网访问配置:从端口放行到公网暴露
服务在服务器本机跑起来了,接下来就到了重头戏:外网访问。这一节的配置因人而异,取决于你的网络环境。我会把三种常见路径都讲清楚,当你实际操作时,先判断自己属于哪种场景,再对号入座。
4.1 先在服务器本机验证端口监听
做任何网络配置之前,先在服务器本机验证服务是否正常监听。命令如下:
bash复制netstat -ano | findstr 8080
如果能看到类似TCP 0.0.0.0:8080 0.0.0.0:0 LISTENING 12345的输出,说明Java进程正在监听8080端口,后面的12345是PID(进程ID)。这里看到监听地址是0.0.0.0很重要,表示它监听所有网卡地址。如果监听地址是127.0.0.1:8080,说明服务只在本机回环地址上监听,外网永远访问不到,需要在Spring Boot配置里加上server.address=0.0.0.0。
如果netstat查不到8080端口,说明服务没起来或监听在其他端口。这时用tasklist | findstr java查Java进程是否存在,再去看日志确认启动状态。
4.2 Windows防火墙放行端口:最隐蔽的一个拦路虎
当你确认服务在监听8080端口,且在服务器本机用浏览器访问http://127.0.0.1:8080能打开页面后,下一步就是让局域网内其他电脑访问。此时最常见的问题就是防火墙拦住了你的端口。
在服务器上执行以下步骤:
- 打开“控制面板” → “Windows Defender防火墙” → “高级设置”。
- 点击左侧“入站规则”,再点右侧“新建规则”。
- 选择“端口”,下一步,选“TCP”和“特定本地端口”,填入
8080。 - 选择“允许连接”,按需勾选“公用”、“域”、“专用”,一般全勾上。
- 给规则起个名字,比如
allow-springboot-8080,完成。
配置好之后,在同一局域网内的另一台电脑上访问http://服务器局域网IP:8080,能打开就说明内网访问通了。
这里分享一个我踩过的坑:给Spring Boot配了server.port=8080,但防火墙放行的是80端口,结果服务本身都起不来(因为80被IIS之类的占用)。所以务必确认你放行的端口,和application.yml里配置的server.port一致,别想当然。
4.3 场景一:云服务器上的部署(推荐大多数项目使用)
如果你部署用的是云服务商的云服务器(比如阿里云、腾讯云),那“外网访问”的防火墙关卡有两层:第一层是Windows系统自带的防火墙(按照4.2配置);第二层是云平台的安全组,它相当于云上的虚拟防火墙。
云服务器安全组的配置步骤是:
- 登录云控制台,进入实例列表,找到你的服务器实例。
- 点“安全组”或“防火墙”配置,一般在实例详情页或网络与安全菜单下。
- 添加一条入方向规则:
- 协议:TCP
- 端口:8080
- 授权对象:0.0.0.0/0(表示任何人都能通过8080访问,也可以填特定IP网段来限制来源)
- 策略:允许
很多新手只配了Windows防火墙,没配云平台安全组,导致云服务器外网访问不通,这类问题我解决过不低于十次。安全组配置完之后,外网访问http://你的云服务器公网IP:8080就能通了。
需要注意的是,如果服务要面向正式生产环境,建议安全组不要开到0.0.0.0/0,而是只放行已知的固定IP。比如你自己办公网出口IP、手机运营商IP,这样能少暴露很多攻击面。
4.4 场景二:没有公网IP时用内网穿透工具
如果你的服务跑在家里或公司内网的Windows机器上,没有公网IP,那内网穿透是最快的方案。这类工具的原理很简单:它在你电脑上起一个客户端,客户端主动连接到穿透服务商的中转服务器;外网用户访问中转服务器上的一个公网地址,中转服务器再把流量通过这个双向隧道转发到你本机的8080端口。
我用过几款主流的内网穿透工具,比如cpolar、花生壳,它们的基本流程差不多:
- 注册账号,下载客户端软件,安装到Windows服务器上。
- 在控制台创建一个隧道,填写本地地址为
127.0.0.1,端口为8080。 - 客户端登录后,控制台会给一个公网访问地址,比如
http://xxxx.imotor.com或https://xxxx.cpolar.top。 - 浏览器访问这个地址,就能穿透到你的Windows服务器上。
这里有一个容易踩的坑:即便用了内网穿透,Windows防火墙仍然可能拦截本地端口。因为内网穿透工具的机制是打包一个“反向代理”请求到本地端口,它最终还是要和127.0.0.1:8080通信,这个属于本机回环流量,理论上防火墙不会拦,但有些安全策略严格的机器可能配置了高级规则。所以按4.2的步骤放行一次8080端口,总归是有必要的。
内网穿透的免费版一般会分配随机域名,且不定期更换地址,只适合开发调试和临时分享。如果你要把一个个人项目长期对外提供访问,建议付费买一个固定的子域名,也不贵。
4.5 场景三:路由器端口映射,配合动态DNS实现固定访问
如果你宽带确实有公网IP,想用家里的Windows服务器对外提供访问,可以用路由器端口映射。流程如下:
- 在路由器管理页(一般是192.168.1.1)找到“端口映射”或“虚拟服务器”设置。
- 添加一条映射规则:外部端口8080,内部IP填Windows服务器的内网IP(比如192.168.1.100),内部端口8080,协议TCP。
- 外网访问时,用
http://你的公网IP:8080就能直达服务器。
但这里有个麻烦:大多数家庭宽带的公网IP是动态的,过几天就变了。解决办法是搭配动态DNS服务。现在很多路由器自带DDNS功能,注册一个免费域名,路由器会定时把当前公网IP绑定到域名上,你访问http://你的域名:8080就行,不用记IP。
这个方案有一个前提绕不开:你的光猫必须是“桥接模式”或“公网IP模式”。如果光猫是运营商默认路由模式,你的路由器只是二级NAT,做端口映射会失效。曾经有朋友问我为什么家里端口映射不生效,我远程一看,光猫WAN口IP是100.64.x.x,铁定的大内网,再怎么配也白搭。
4.6 外网访问的端口选择:80、443、还是8080?
最后给个建议:外网访问的端口,能不用8080就别用8080。原因有两个:
- 很多公共网络或企业网络对非标准端口有出站限制,8080虽然常见,但并不是所有地方都能访问。
- 80端口是HTTP默认端口,访问时不用输端口号;443是HTTPS默认端口,用起来更正规。
但80和443端口在Windows上默认容易被别的程序占用,比如IIS、SQL Server Reporting Services等。我处理过的场景里,最常见的是“端口被占用导致Spring Boot启动失败”。所以如果你确实要用80端口,先确认这个端口空闲,或者把占用它的程序停掉/换端口。如果用了内网穿透工具,你不用操心本地端口是不是80,你只需要把本地8080映射出去,穿透服务商那边的公网端口可以是80或443,访问体验上一样是http://xxx.穿透域名,不需要输8080。
5. 常见问题与排查技巧:从启动失败到外网不通
这部分内容是我最想分享的。部署这种事,顺利的时候5分钟搞定,不顺利的时候能卡一整天。下面这几个问题,都是我在实际操作中反复遇到过的,整理成速查表,再逐个说排查思路。
5.1 典型问题速查表
| 问题表现 | 可能原因 | 解决办法 |
|---|---|---|
| 双击jar包提示“没有主清单属性” | Spring Boot repackage未生效 | 检查pom.xml是否引入spring-boot-maven-plugin,重新clean package |
| jar包启动后立即退出,无报错 | 端口被占用 / 数据库连不上 / JDK版本不符 | 看日志,重点看ERROR行;换端口或修配置 |
| 本机能访问,局域网不能访问 | Windows防火墙未放行端口 | 添加入站规则,放行对应TCP端口 |
| 局域网能访问,外网不能访问 | 云安全组未放行 / 宽带无公网IP / 端口映射错误 | 按自己网络场景对照4.3~4.5逐一排查 |
| 日志中文乱码 | Windows默认GBK和项目UTF-8冲突 | 启动参数加-Dfile.encoding=UTF-8,cmd执行chcp 65001 |
| 服务跑一段时间后内存飙升 | JVM堆设置不合理或代码有内存泄漏 | 设置-Xms和-Xmx,配合JVisualVM等工具做堆转储分析 |
| 覆盖jar包时提示文件被占用 | 服务未停止 | 先nssm stop MyProjectService或结束java进程再替换 |
| 外网访问时提示连接被重置 | 运营商封了80/443端口 / 防火墙规则未刷新 | 换非标准端口,或使用HTTPS并通过内网穿透工具走公网端口 |
5.2 端口占用问题:从netstat到定位进程
端口被占用是Windows部署中最常见的启动失败原因。表现为:启动jar包时报Port 8080 was already in use.或Web server failed to start。排查和解决步骤:
bash复制netstat -ano | findstr 8080
这条命令会列出占用8080端口的PID。假设PID是12345,继续执行:
bash复制tasklist | findstr 12345
看到是java.exe,说明之前启动了一个Java进程还没停干净。如果是别的程序,比如System或inetinfo.exe(IIS),就用下面的命令结束它,或者换一个端口:
bash复制taskkill /PID 12345 /F
提示:在正式服务器上,
taskkill /F之前先确认这个进程不是其他关键服务。如果不确定,换端口比强制杀进程更稳妥,把application-prod.yml里的server.port改成8081,重新启动即可。
5.3 外网不通的排查顺序:别一上来就怀疑防火墙
外网不通这个问题,新手最容易陷入“反复开关防火墙”的无效循环里。我给你一个稳定的排查顺序,按照这个顺序做,基本能定位90%的问题:
- 在服务器本机访问
http://127.0.0.1:8080,能通说明服务本身OK;不通先解决服务。 - 用
netstat -ano | findstr 8080确认监听地址是0.0.0.0,而不是127.0.0.1。后者说明服务只绑了回环地址,需要改配置。 - 在局域网另一台电脑上访问服务器局域网IP,假设为
http://192.168.1.100:8080。能通则说明Windows防火墙已放行或未拦截;不通则检查防火墙入站规则。 - 在云服务器控制台检查安全组是否放行8080端口。这一步被忽略的频率极高。
- 如果用了路由器映射,检查路由器WAN口是否真的有公网IP,以及端口映射规则是否正确。
- 如果用了内网穿透,检查穿透客户端的隧道是否在线,控制台显示的本地服务是否指向了正确的端口。
这个顺序的核心逻辑是“由近到远,从服务本身到网络链路”。每次只动一个变量,别同时改防火墙、端口映射、穿透配置,否则出了问题你根本不知道是哪个环节导致的。
5.4 使用日志定位问题:日志文件是你最信任的伙伴
所有部署问题的最终答案,都在日志里。Spring Boot默认输出到console的日志,用了我的start.bat或NSSM配置后,会写到logs目录。排查任何问题,第一步都应该是打开最新的日志文件,搜索关键字:
ERROR—— 直接看错误信息,通常是数据库连接失败、bean创建失败、配置缺失等。APPLICATION FAILED TO START—— Spring Boot的大段红色提示,会直接告诉你失败原因。Caused by—— 如果你在手写异常栈,找到Caused by这一行,往往就是根本原因的开始。
如果你的项目配置了综合日志(比如Logback),日志文件会自动滚动,按日期切分。Windows环境下有一个需要注意的问题:日志文件被Java进程占用,导致你无法用文本编辑器打开或删除。这种情况下,要么停服务再处理日志,要么用支持“以共享方式打开”的工具,比如Notepad++或VS Code,它们可以读取被占用的日志。
5.5 安全加固:部署后一定要做的几件小事
项目能够外网访问之后,马上就面临暴露在公网的安全问题。我不想在这里制造焦虑,但以下三件事建议一定要做:
- 修改Spring Boot默认用户名密码。如果你使用了Spring Security,或者项目里有一个管理后台,务必把默认密码换掉。不要用
admin/admin这种组合,公网扫描工具分分钟扫出来。 - 不去改动系统固有的防火墙规则。有很多人在部署失败后,气急败坏之下选择“关闭Windows防火墙”,这个方法让外网通了,但也把自己的系统敞开了大门。正确做法是只放行必要端口,保留防火墙开启状态。
- 定期看日志,关注异常访问。如果你的日志里出现大量非预期的请求,比如频繁访问不存在的路径,那大概率是被人扫描了。不用太慌,只要端口不暴露数据库和内部管理接口,一般问题不大,但要及时发现异常。
6. 一点个人经验:部署顺序和脚本化的重要性
踩过这么多坑,总结下来就一句话:部署的顺序一定不能乱。先确保本地能打包、本地能运行,再传jar包到服务器,然后做进程守护和开机自启,最后再配置网络访问。每一步验证通过后再进入下一步,效率最高。反过来,有些人先跑去配路由器端口映射,配了半天发现jar包没起来,白白浪费两小时。
每次部署完,我建议顺手做两件事:
- 把服务器上的目录结构、启动命令、NSSM服务名、防火墙规则、安全组规则、穿透隧道信息整理成一份简单的部署文档,哪怕就是几十行字。下次升级部署时,照着自己的文档操作,完全不用重新回忆。
- 把start.bat和部署流程脚本化。你可能会觉得“就一个项目,手动部署就行”,但当你同时维护三个项目、每周都要发版时,脚本能减少大量重复操作,还能避免人为失误。
最后再分享一个小技巧:在生产服务器上,尽量别在cmd窗口里直接跑java -jar。黑窗口一关,服务就没了;电脑休眠,服务也可能中断。用NSSM或winsw这类工具把Java应用注册成Windows服务,设置开机自启,才是正式部署的姿态。我最初也是在cmd窗口里跑jar包,后来有一次服务器因为系统更新自动重启,所有项目全部掉线,才下决心改成服务方式,从此再也不用半夜跑机房去手动启动服务了。
