在 Debian 上部署 Java 应用,难点通常不在某一条命令,而在于环境、编译、打包和运行方式是否连得起来。下面按实际部署顺序,把 OpenJDK 安装、本地编译、JAR 打包、服务器启动和 systemd 托管串成一套可复用流程,读完你可以判断自己该装 JRE 还是 JDK、什么时候需要可执行 JAR,以及何时该把手工启动切换成系统服务。
准备环境:先更新 Debian,再安装 Java
部署前先把系统状态整理好,避免后面因为包版本或运行环境问题反复排查。Debian 上推荐直接使用 OpenJDK,系统仓库默认支持,安装和维护都比较省事。
安装 OpenJDK 11,并确认命令可用
# 更新系统软件包列表及已安装的包
sudo apt update && sudo apt upgrade -y
# 安装OpenJDK 11(可根据需求替换为17、21等版本,如`openjdk-17-jdk`)
sudo apt install openjdk-11-jdk -y
# 验证安装(输出Ja va版本信息则表示成功)
ja va -version
这里安装的是 openjdk-11-jdk,它除了运行时之外,还自带编译器 ja vac。如果你的服务器只负责运行程序、不需要现场编译,那么换成更轻量的 openjdk-11-jre 也可以。
如何在 Debian 上编译 Java 应用
如果代码需要直接在 Debian 机器上编译,先确认源码目录结构清晰。以 src/com/example/YourMainClass.ja va 为例,可以先把编译输出单独放到 out 目录,方便后续打包。
基础编译流程
# 创建输出目录(用于存放编译后的.class文件)
mkdir -p out
# 编译Ja va源文件(指定源文件目录`src`,输出到`out`目录)
ja vac -d out src/com/example/YourMainClass.ja va
# 验证编译结果(`out`目录下应生成对应的.class文件)
ls out/com/example/
有第三方依赖时,别漏掉类路径
如果项目依赖外部库,编译时必须显式指定类路径,否则常见报错就是“找不到类”或“符号无法解析”。原文给出的写法如下:
ja vac -cp "libs/*":src -d out src/com/example/YourMainClass.ja va
-cp 的作用就是告诉编译器去哪里找依赖。对小项目来说,这一步往往比编译命令本身更容易出问题,尤其是在手工管理 libs 目录时。
把 class 文件打包成可执行 JAR
编译完成后,通常会进一步打包成可执行 JAR,这样部署、传输和启动都更统一。关键点在于 MANIFEST.MF 里要声明主类,否则 ja va -jar 无法直接启动。

先写 MANIFEST.MF,再执行打包
# 创建MANIFEST.MF文件(指定主类,如`com.example.YourMainClass`)
echo "Manifest-Version: 1.0" > MANIFEST.MF
echo "Main-Class: com.example.YourMainClass" >> MANIFEST.MF
# 打包为JAR(`-C out .`表示切换到`out`目录后打包所有内容)
jar cfm your-app.jar MANIFEST.MF -C out .
# 验证JAR包(输出主类信息则表示打包成功)
jar tf your-app.jar
完成后,可以直接用 ja va -jar your-app.jar 测试是否能够启动。对单体应用来说,这种方式比手工指定主类和类路径更适合部署阶段使用。
将 JAR 上传到 Debian 服务器
本地打好包之后,下一步就是把 JAR 文件传到服务器。原文采用的是最直接的 scp 方式,适合手工部署或小规模环境。
# 将本地`your-app.jar`上传至服务器`/opt/ja va-apps`目录(需提前创建)
scp your-app.jar user@your-server-ip:/opt/ja va-apps/
上传后建议立刻检查目标文件是否存在,避免后面启动时才发现路径写错:
ls -l /opt/ja va-apps/your-app.jar
/opt/ja va-apps 这种目录约定比较适合放业务应用文件,实际使用中也可以按团队规范换成别的路径,但要确保后续启动命令和服务文件保持一致。
运行 JAR:前台启动还是后台常驻
JAR 上传到服务器后,就可以直接运行。临时测试时,前台启动最直观;需要断开 SSH 后仍保持运行,则要改成后台方式。
两种常见启动方法
# 运行JAR(指定JAR路径)
ja va -jar /opt/ja va-apps/your-app.jar
# 若需后台运行(脱离终端),可使用`nohup`或`&`
nohup ja va -jar /opt/ja va-apps/your-app.jar > app.log 2>&1 &
其中几个参数分别负责不同的事情:
nohup:防止进程因终端关闭而终止;> app.log:把标准输出写入app.log;2>&1:把错误输出合并到标准输出。
这种方式适合快速上线或临时运行,但如果你需要更稳定的进程管理、开机自启和统一状态查看,最好继续往下配置 systemd。
用 systemd 设置开机自启动
对于长期运行的 Java 服务,systemd 是 Debian 上更规范的托管方式。它能把启动命令、重启策略、运行用户和自启动行为集中到一个服务文件里管理。

创建服务文件并写入启动参数
# 创建服务文件(`your-app.service`)
sudo nano /etc/systemd/system/your-app.service
# 写入以下内容(根据实际情况修改`User`、`ExecStart`路径)
[Unit]
Description=Your Ja va Application
After=network.target
[Service]
User=www-data
# 建议使用非root用户(如www-data、appuser)
ExecStart=/usr/bin/ja va -jar /opt/ja va-apps/your-app.jar
SuccessExitStatus=143
# 处理JVM正常退出信号
Restart=on-abort
# 异常退出时自动重启
RestartSec=10
# 重启间隔10秒
[Install]
WantedBy=multi-user.target
# 保存并退出(Ctrl+O→回车→Ctrl+X)
# 启用服务(设置开机自启)
sudo systemctl enable your-app.service
# 启动服务
sudo systemctl start your-app.service
# 查看服务状态(确认运行正常)
sudo systemctl status your-app.service
这里有两个容易被忽略的点。第一,User=www-data 只是示例,生产环境应替换成实际的应用用户;第二,ExecStart 里的 Java 路径和 JAR 路径必须与服务器实际安装位置一致,否则服务会启动失败。
需要多个 Java 版本时怎么切换
如果一台 Debian 服务器上同时跑多个项目,常见情况就是项目对 Java 版本要求不同,比如一个仍停留在 11,另一个已经切到 17。此时可以用 update-alternatives 管理默认版本。
# 注册Ja va版本到alternatives系统(以OpenJDK 11和17为例)
sudo update-alternatives --install /usr/bin/ja va ja va /usr/lib/jvm/ja va-11-openjdk-amd64/bin/ja va 1100
sudo update-alternatives --install /usr/bin/ja va ja va /usr/lib/jvm/ja va-17-openjdk-amd64/bin/ja va 1700
# 切换默认Ja va版本(交互式选择)
sudo update-alternatives --config ja va
# 验证当前默认版本
ja va -version
切换后一定要重新确认 ja va -version 输出是否符合预期。如果服务文件里依赖系统默认的 ja va 命令,这一步会直接影响应用实际运行的 JVM 版本。
部署时最值得优先确认的几件事
把这套流程压缩来看,Debian 上部署 Java 应用主要就是五个环节:先装对 OpenJDK,再把源码编译成 .class,接着打包成可执行 JAR,然后上传到服务器并启动,最后视需要交给 systemd 托管。真正容易踩坑的地方通常集中在三处:JDK 和 JRE 选错、编译时类路径缺失、服务文件里的用户和路径配置不一致。







