Java 项目在 Ubuntu 上如何部署:从 JDK、JAR 到 systemd 与 Nginx

小石头
小石头
发布时间:2026-08-25 | 149人浏览过
原创

前言

很多 Java 项目本地运行正常,但真正部署到 Ubuntu 服务器后,往往会卡在环境版本、进程托管或外部访问这些细节上。本文按实际部署顺序,把 JDK 安装、JAR 打包上传、三种运行方式,以及防火墙、Nginx 和自动化发布串起来,帮助你判断测试环境和生产环境分别该怎么做。

很多 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/ 目录下

无论用哪种构建工具,部署时都要先确认最终生成的是你要上线的那个包,尤其要留意版本号、环境配置和依赖是否与预期一致。

Java 项目在 Ubuntu 上的部署流程图,展示从安装 JDK、打包 JAR、上传服务器到选择运行方式的顺序关系。
Ubuntu 部署 Java 项目主流程从环境准备到应用启动,先把部署链路走通,再决定采用哪种运行方式。

把 JAR 传到 Ubuntu 服务器

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

Java 服务对外访问配置图,展示应用端口、防火墙放行和 Nginx 反向代理之间的关系。
端口放行与反向代理关系应用能启动只是第一步,端口放行和代理入口决定了服务能否稳定对外。
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_USER
  • SERVER_PASSWORD
  • SERVER_IP
  • DEPLOY_PATH

把这些敏感信息放进 Secrets 后,工作流就能在不暴露凭据的前提下连接服务器。对于已经稳定运行的项目,这一步能明显减少人工操作失误,也更适合团队协作。

部署时该怎么选

如果只是验证程序能否启动,用 java -jar 前台运行就够了;想快速挂后台,可以用 nohup;而只要进入长期运行或生产环境,systemd 通常是更值得优先采用的方案。

在此基础上,面向外部访问的项目别忘了检查防火墙端口是否开放;需要域名、统一入口或 HTTPS 时,再补上 Nginx。至于自动化部署,可以等手工流程跑顺以后再接入,这样排障路径会更清楚,也更容易维护。

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表