很多 Java 项目本地能跑,不代表上了 Ubuntu 就能稳定对外提供服务。部署时真正容易出问题的,通常不是打包本身,而是运行方式、服务托管、端口开放以及是否需要反向代理。下面按一条常见的上线路径来拆解:先装好运行环境,再生成并上传 JAR,随后根据场景选择前台、nohup 或 systemd 运行,最后补上防火墙、Nginx 和自动化部署这些常见的生产配置。
安装 Java 运行环境
在 Ubuntu 上部署 Java 项目,第一步是把运行环境准备好。这里使用比较常见的 OpenJDK 11,适合大多数常规服务端项目。
- 更新软件包列表:
sudo apt update - 安装 OpenJDK 11:
sudo apt install openjdk-11-jdk - 验证安装结果:
java -version
如果命令输出了对应的 Java 版本信息,就说明 JDK 已经可用。对部署来说,这一步的意义不只是“装上即可”,还在于后面的 systemd 配置、CI 构建环境和本地打包版本最好保持一致,避免出现“本地能跑、服务器报错”的情况。
打包项目并上传到服务器
运行环境就绪后,下一步是把项目打成可执行文件。前提是代码已经完成开发并通过测试,部署机只负责运行,不建议在服务器上临时改代码再编译。
按构建工具生成 JAR
- 如果使用 Maven,在项目根目录执行:
mvn clean package - 构建完成后,JAR 文件通常位于
target/目录,例如:myapp-1.0.0.jar - 如果使用 Gradle,则执行:
gradle build - 对应产物通常位于
build/libs/目录下
无论用哪种构建工具,部署时都要先确认最终生成的是你要上线的那个包,尤其要留意版本号、环境配置和依赖是否与预期一致。

把 JAR 传到 Ubuntu 服务器
打包完成后,可以直接用 scp 上传文件。这种方式足够简单,也适合单机部署和临时发布。

scp target/myapp-1.0.0.jar username@your_server_ip:/path/to/deploy
其中,username 需要替换成服务器用户名,your_server_ip 替换成目标服务器 IP,/path/to/deploy 替换成你实际使用的部署目录。
如果你的项目是第一次部署,建议先在服务器上固定一个目录用于存放 JAR 和日志文件,后续无论是手动更新还是 systemd 托管,路径都更清晰。
项目怎么运行:测试、后台与生产环境三种方式
上传完成后,就进入真正的运行阶段。这里没有唯一答案,关键看你是做临时验证,还是要长期稳定对外服务。
前台运行:适合临时测试
如果只是想快速验证应用能不能在服务器上启动,可以直接执行:
java -jar /path/to/deploy/myapp-1.0.0.jar
这种方式最直接,日志也会实时打印在当前终端里,但缺点同样明显:终端一关,进程就停止,不适合正式使用。
后台运行:适合简单常驻
如果你只想先让服务挂在后台持续运行,可以使用 nohup:
nohup java -jar /path/to/deploy/myapp-1.0.0.jar > /path/to/deploy/app.log 2>&1 &
这样即使终端关闭,应用也会继续运行,标准输出和错误输出都会写入 app.log。它的优点是命令少、上手快,缺点是进程管理比较粗放,遇到崩溃、重启、开机自启等需求时不够方便。
systemd 托管:生产环境更稳妥
如果项目要长期在线,通常会把它注册为 systemd 服务。这样可以获得更好的进程管理能力,包括开机自启、异常自动重启和统一查看状态。
先创建服务文件:
sudo vim /etc/systemd/system/myapp.service
写入如下内容,并根据你的实际用户名、JAR 路径和内存参数调整:
[Unit]
Description=My Java Application
After=network.target
[Service]
User=your_username
WorkingDirectory=/path/to/deploy
ExecStart=/usr/bin/java -Xms512m -Xmx1024m -jar /path/to/deploy/myapp-1.0.0.jar
Restart=always
RestartSec=3
Environment="JAVA_OPTS=-Xms512m -Xmx1024m"
[Install]
WantedBy=multi-user.target
配置完成后,按顺序执行以下命令:
- 重新加载服务配置:
sudo systemctl daemon-reload - 启动服务:
sudo systemctl start myapp - 设置开机自启:
sudo systemctl enable myapp - 查看服务状态:
sudo systemctl status myapp
如果状态中显示 active (running),就说明服务已经成功拉起。对于生产环境来说,这通常是比 nohup 更可靠的默认选择。
让外部能访问:防火墙与 Nginx 反向代理
应用跑起来之后,不代表外部一定能访问到。服务器常见的两个补充动作,一是放行监听端口,二是根据域名访问需求接入 Nginx。
开放应用端口
如果你的 Java 项目是 Web 应用,并且监听例如 8080 端口,就需要在 Ubuntu 的防火墙里放行对应规则。以默认常见的 ufw 为例:
sudo ufw allow 8080/tcp
然后检查状态:
sudo ufw status
如果输出中出现 8080/tcp ALLOW,说明端口已经开放成功。这里要注意,开放的端口应当与应用实际监听端口一致,否则服务虽然在运行,外部还是连不上。
通过 Nginx 提供域名访问
如果你希望用户直接通过域名访问应用,或者准备进一步接入 HTTPS,那么在 Java 服务前面加一层 Nginx 反向代理会更常见。
- 安装 Nginx:
sudo apt install nginx - 编辑配置文件:
/etc/nginx/conf.d/myapp.conf
可以写入如下示例配置,把域名和端口替换成你的实际值:
server {
listen 80;
server_name your_domain.com;
location / {
proxy_pass http://localhost: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;
}
}
修改完成后重启 Nginx:
sudo systemctl restart nginx
这种做法的好处在于,Java 应用仍然只需要监听本地端口,而域名入口、转发规则以及后续的 HTTPS 证书,都可以交给 Nginx 统一处理。
需要频繁发布时,可以加上自动化部署
如果项目由团队共同维护,或者发布频率比较高,手工打包、上传、重启服务很快会变成重复劳动。这时可以考虑把构建和部署交给 CI/CD 工具处理,例如 GitHub Actions。
在项目根目录创建 .github/workflows/deploy.yml,示例内容如下:
name: Deploy Java App
on:
push:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'adopt'
- name: Build with Maven
run: mvn -B package --file pom.xml
- name: Upload to Server
run: |
sshpass -p ${{ secrets.SERVER_PASSWORD }} scp -o StrictHostKeyChecking=no target/*.jar ${{ secrets.SERVER_USER }}@${{ secrets.SERVER_IP }}:${{ secrets.DEPLOY_PATH }}
sshpass -p ${{ secrets.SERVER_PASSWORD }} ssh -o StrictHostKeyChecking=no ${{ secrets.SERVER_USER }}@${{ secrets.SERVER_IP }} "systemctl restart myapp"
这套流程的核心是:代码推送到 main 分支后,自动拉取仓库、配置 JDK 11、执行 Maven 构建,再把生成的 JAR 上传到服务器,并通过 systemctl restart myapp 重启服务。
另外,还需要在 GitHub 仓库的 Settings > Secrets and variables > Actions 中配置这些密钥:
SERVER_USERSERVER_PASSWORDSERVER_IPDEPLOY_PATH
把这些敏感信息放进 Secrets 后,工作流就能在不暴露凭据的前提下连接服务器。对于已经稳定运行的项目,这一步能明显减少人工操作失误,也更适合团队协作。
部署时该怎么选
如果只是验证程序能否启动,用 java -jar 前台运行就够了;想快速挂后台,可以用 nohup;而只要进入长期运行或生产环境,systemd 通常是更值得优先采用的方案。
在此基础上,面向外部访问的项目别忘了检查防火墙端口是否开放;需要域名、统一入口或 HTTPS 时,再补上 Nginx。至于自动化部署,可以等手工流程跑顺以后再接入,这样排障路径会更清楚,也更容易维护。









