Report this

What is the reason for this report?

Install Apache Maven on Ubuntu with JDK 17, SDKMAN, CI/CD Automation

Updated on August 26, 2025
Install Apache Maven on Ubuntu with JDK 17, SDKMAN, CI/CD Automation

Apache Maven is a cornerstone tool for building and managing Java projects, trusted by developers worldwide. This guide will walk you through installing the latest version of Maven on Ubuntu, ensuring your development environment is robust, up-to-date, and ready for any Java project—whether you’re just starting out or managing complex enterprise builds. Let’s get your system set up for seamless Java development with Maven.

Introduction

This guide provides step-by-step instructions for installing Apache Maven 3.9.9 on Ubuntu with JDK 17, covering multiple installation methods, configuration, troubleshooting, and frequently asked questions.

Key Takeaways

  • JDK 17 (LTS) is the recommended Java version for Maven installations due to long-term support and stability. Java Development Kit (JDK) 17 is a Long-Term Support (LTS) release, meaning it receives updates and security patches for several years, making it a reliable foundation for enterprise and production environments. Using JDK 17 ensures compatibility with the latest Maven features and plugins, and it is widely supported by the Java ecosystem, reducing the risk of encountering deprecated or unsupported APIs.

  • Apache Maven 3.9.9 is the latest stable version at the time of writing. Apache Maven 3.9.9 introduces important bug fixes, performance improvements, and enhanced compatibility with modern Java versions. Staying up to date with the latest Maven release ensures access to new features, improved dependency resolution, and better integration with CI/CD tools. It also helps avoid issues caused by outdated plugins or incompatibilities with recent Java releases.

  • Multiple installation methods are available: apt, binaries, SDKMAN, and automation scripts. You can install Maven on Ubuntu using several approaches: the apt package manager for convenience, downloading official binaries for full control, SDKMAN for easy version management and switching, or automation scripts for reproducible, idempotent setups in CI/CD pipelines. Each method has trade-offs in terms of version freshness, ease of updates, and suitability for automation or production use.

  • Setting environment variables like JAVA_HOME and M2_HOME is essential for proper configuration. Correctly configuring environment variables such as JAVA_HOME (pointing to your JDK installation) and M2_HOME (pointing to your Maven directory) is crucial for Maven and Java tools to function as expected. Adding these variables to your shell profile and ensuring they are included in your PATH allows both Maven and Java commands to be recognized system-wide, preventing common errors during builds.

  • Verification commands ensure both JDK and Maven are installed correctly. After installation, running java -version and mvn -version in your terminal confirms that both Java and Maven are properly set up and accessible from your environment. These commands display the installed versions and their paths, helping you quickly identify misconfigurations or version mismatches before starting development or automation tasks.

  • Sample Maven project creation helps validate the installation. Creating and building a sample Maven project is a practical way to verify that your Maven setup works end-to-end. By generating a new project with mvn archetype:generate and running a build, you can ensure that dependencies are resolved, plugins function correctly, and your environment is ready for real-world Java development. This step also familiarizes you with Maven’s workflow and project structure.

What is Apache Maven?

Apache Maven is a powerful build automation and project management tool primarily used for Java projects. It simplifies the build process, dependency management, and project documentation through a standardized project structure and configuration using XML files (pom.xml).

Who Should Use Maven?

Maven is an essential tool for developers at all skill levels. For beginners, it simplifies the complex process of building Java applications by managing dependencies and providing a standardized project structure. Intermediate developers benefit from its robust lifecycle management and easy integration with continuous integration/continuous deployment (CI/CD) pipelines, which streamline development workflows. Advanced developers appreciate Maven’s extensibility and support for complex multi-module projects, making it an indispensable tool for scalable and maintainable software development.

By automating builds and managing dependencies, Maven reduces manual errors and ensures consistent project setups across teams. Its strong integration with popular CI/CD tools helps teams deploy applications reliably and efficiently, making it a valuable asset in modern software development environments.

Prerequisites

Before installing Maven, ensure you have:

  • A Linux system (preferably Ubuntu for this tutorial)
  • Basic command line knowledge.
  • Internet connectivity to download packages and binaries
  • Administrative privileges (sudo access) for installation steps
  • Java Development Kit installed (preferably JDK 17). If you need help, check out our How To Install Java on Ubuntu guide.

Install Java (OpenJDK 17 on Ubuntu)

JDK 17 is the recommended Java version for Maven. You can install it via Ubuntu’s package manager or, optionally, from an official tarball for finer control.

Install OpenJDK 17 using Ubuntu’s package manager for simplicity and security updates:

sudo apt update
sudo apt install openjdk-17-jdk

Set JAVA_HOME and add it to your PATH (add these lines to your ~/.profile or ~/.bashrc):

export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
export PATH="$JAVA_HOME/bin:$PATH"

Apply the changes:

source ~/.profile

Verify the installation:

java -version

Expected output:

openjdk version "17.0.x"
OpenJDK Runtime Environment (build 17.0.x+...)
OpenJDK 64-Bit Server VM (build 17.0.x+..., mixed mode, sharing)

Optional: Install from Tarball (Temurin)

For maximum control or to use the Adoptium Temurin distribution, download and install the tarball:

wget https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.10+7/OpenJDK17U-jdk_x64_linux_hotspot_17.0.10_7.tar.gz
tar -xvf OpenJDK17U-jdk_x64_linux_hotspot_17.0.10_7.tar.gz
sudo mv jdk-17.0.10+7 /opt/jdk-17

Set JAVA_HOME and update your PATH (add to ~/.profile or ~/.bashrc):

export JAVA_HOME=/opt/jdk-17
export PATH="$JAVA_HOME/bin:$PATH"

Apply the changes:

source ~/.profile

Verify:

java -version

Install Maven on Ubuntu

There are several ways to install Maven. Choose the method that best fits your requirements.

Install via APT

You can install Maven using Ubuntu’s package manager. Note: The version may be outdated compared to upstream releases.

sudo apt update
sudo apt install maven

Tip: Use -y with apt install for unattended, non-interactive upgrades or automation contexts.

Verify the installed version:

mvn -version

If you require the latest Maven version, consider the binary or SDKMAN installation methods below.

Example usage after APT installation:

mvn compile
mvn package

The mvn compile command compiles your project’s source code, turning it into executable bytecode. The mvn package command then takes the compiled code and bundles it into a distributable format, such as a JAR or WAR file.

Install from Binary (3.9.9)

Download the official Apache Maven 3.9.9 binary archive, extract it, and configure environment variables.

wget https://dlcdn.apache.org/maven/maven-3/3.9.9/binaries/apache-maven-3.9.9-bin.tar.gz
tar -xvf apache-maven-3.9.9-bin.tar.gz
sudo mv apache-maven-3.9.9 /opt/
# Verify checksum
wget https://downloads.apache.org/maven/maven-3/3.9.9/binaries/apache-maven-3.9.9-bin.tar.gz.sha512
sha512sum -c apache-maven-3.9.9-bin.tar.gz.sha512

# Optional: verify signature with KEYS
wget https://downloads.apache.org/maven/KEYS
gpg --import KEYS
gpg --verify apache-maven-3.9.9-bin.tar.gz.asc apache-maven-3.9.9-bin.tar.gz

Set M2_HOME and update your PATH (add to ~/.profile or ~/.bashrc):

export M2_HOME=/opt/apache-maven-3.9.9
export PATH="$M2_HOME/bin:$PATH"

Apply the changes:

source ~/.profile

Verify:

mvn -version

Expected output:

Apache Maven 3.9.9 (9f3a6d9b4e9a6e0a5e9b7a3f6e1b5f1d3c1a7b2c)
Maven home: /opt/apache-maven-3.9.9
Java version: 17, vendor: Eclipse Adoptium, runtime: /usr/lib/jvm/java-17-openjdk-amd64
Default locale: en, platform encoding: UTF-8
OS name: "linux", version: "5.15.0-58-generic", arch: "amd64", family: "unix"

Note: Depending on whether you installed OpenJDK via APT or Temurin via tarball, the Java runtime path may show /usr/lib/jvm/java-17-openjdk-amd64 or /opt/jdk-17.

Install via SDKMAN (3.9.9)

SDKMAN is a tool for managing parallel versions of multiple Software Development Kits, including Java and Maven.

Install SDKMAN:

curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"

Install Maven 3.9.9:

sdk install maven 3.9.9

Verify:

mvn -version

Managing Maven versions with SDKMAN:

sdk use maven 3.9.9
sdk list maven

sdk use maven <version> allows you to switch between Maven versions on the fly. sdk list maven shows all available Maven versions.

Use the Maven Wrapper

The Maven Wrapper (mvnw) is a script that allows you to run a Maven project with a specific Maven version without requiring Maven to be installed globally on your system. This ensures consistent builds across different environments and team members.

Usage example:

./mvnw clean install

Running ./mvnw clean install will download the required Maven version automatically if not present and execute the build lifecycle phases. This approach reduces setup complexity and avoids version conflicts in team environments.

Note: Maven Wrapper is often preferred in teams to guarantee build consistency and ease onboarding.

Configure Environment Variables

Properly setting environment variables ensures that Java and Maven work as expected.

Add the following lines to your ~/.profile or ~/.bashrc (adjust the paths as needed for your installation method):

For APT-based OpenJDK 17:

export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64

For tarball-based OpenJDK (Temurin):

export JAVA_HOME=/opt/jdk-17

For Maven (binary install):

export M2_HOME=/opt/apache-maven-3.9.9

Add both to your PATH:

export PATH="$JAVA_HOME/bin:$M2_HOME/bin:$PATH"
# System-wide (all users)
sudo tee /etc/profile.d/maven.sh >/dev/null <<'EOF'
export M2_HOME=/opt/apache-maven-3.9.9
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
export PATH="$JAVA_HOME/bin:$M2_HOME/bin:$PATH"
EOF
sudo chmod +x /etc/profile.d/maven.sh

Apply the changes:

source ~/.profile

Verify:

echo $JAVA_HOME
echo $M2_HOME
which mvn

Verify Installation

To confirm Maven and Java are installed correctly:

mvn -version
java -version

You should see Maven version, Java version, and environment details confirming successful installation.

Implementation Example (Hello World)

How to create and run a simple Maven project:

  1. Create a new directory and navigate into it:

    mkdir maven-hello-world
    cd maven-hello-world
    
  2. Generate a Maven project using the archetype plugin:

    mvn archetype:generate -DgroupId=com.example -DartifactId=hello-world -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
    
  3. Navigate to the project directory:

    cd hello-world
    
  4. Compile the project:

    mvn compile
    

    Or package it as a JAR:

    mvn package
    
  5. Run the Java application:

    java -cp target/hello-world-1.0-SNAPSHOT.jar com.example.App
    

Expected output:

Hello World!

This confirms your Maven installation is working correctly.

Decision Guide (APT vs Binary vs SDKMAN vs Automation)

Method Version Freshness Upgrade Path Idempotent? Corporate Policy Friendly? Offline Install Support Pros Cons Recommended For
apt Low (often outdated) Manual (via apt upgrade) Yes High (uses system package manager) Medium (with apt cache) Simple, native integration, minimal setup May not have latest Maven/Java versions Beginners or quick system-native installs
Binaries High (latest release) Manual (replace tarball and symlink) Yes Medium (manual paths) High Full control, version pinning, portable Requires manual setup and env var configuration Developers who want control and latest features
SDKMAN Very High (multi-version) Automated (sdk upgrade/use) Yes Medium (user-level tool) Low Easiest multi-version management, rapid switching Requires extra tool, may not comply with corp policy Devs managing multiple Java/Maven versions or testing
Automation (Ansible/Bash) Configurable Scripted upgrade logic Yes High (auditable, repeatable) High Infrastructure-as-code, CI/CD ready, repeatable installs Requires scripting knowledge and maintenance Teams, DevOps, repeatable infra setup

Note: APT and Snap may have larger footprints due to packaging overhead. In air-gapped or disk-constrained environments, binaries or automation scripts are often preferred.

Choose the method that best fits your needs based on your expertise and environment requirements.

Troubleshooting

What to do if java or mvn commands are not found?

  • Ensure environment variables JAVA_HOME and M2_HOME are correctly set.
  • Confirm that $JAVA_HOME/bin and $M2_HOME/bin are in your PATH.
  • Run source ~/.profile or restart your terminal after changes.

Switch Java versions on Ubuntu

If multiple Java versions are installed, you can select the active version:

sudo update-alternatives --config java

Follow the prompts to select the desired Java version. Then ensure JAVA_HOME matches the selected version.

Maven build fails with “Could not find artifact” errors?

  • Check your internet connection.
  • Verify your settings.xml in ~/.m2 for repository configurations.
  • Clear your local repository cache by deleting ~/.m2/repository.

Example settings.xml for proxy and mirror configuration

Edit your ~/.m2/settings.xml to add proxies and mirrors if needed:

<settings>
  <proxies>
    <proxy>
      <id>example-proxy</id>
      <active>true</active>
      <protocol>http</protocol>
      <host>proxy.example.com</host>
      <port>8080</port>
    </proxy>
  </proxies>
  <mirrors>
    <mirror>
      <id>central-mirror</id>
      <mirrorOf>central</mirrorOf>
      <url>https://your-mirror/repo</url>
    </mirror>
  </mirrors>
</settings>

Wrong Java version detected by Maven?

  • Make sure JAVA_HOME points to the correct JDK 17 directory.
  • Run java -version and mvn -version to confirm versions.

Advanced Usage and Optimization

Using Maven in CI/CD Pipelines with Docker

Here’s an example Dockerfile snippet to install Maven in a CI/CD environment:

FROM ubuntu:22.04

RUN apt-get update && apt-get install -y openjdk-17-jdk maven

WORKDIR /app

COPY . .

RUN mvn clean install

Tip: Add -y to apt-get install (as shown) for non-interactive installs in CI/CD pipelines.

This setup allows you to build your Java projects inside a container, ensuring a consistent environment across all stages of your CI/CD pipeline.

Note: Containerizing builds improves reproducibility and isolates dependencies from the host system.

Performance Optimization Tips

mvn -T 1C clean install

Using the -T 1C flag enables parallel builds utilizing one thread per CPU core, significantly speeding up compilation and packaging. Additionally, configuring mirrors in your settings.xml can improve dependency download speeds by using geographically closer repositories.

Note: Parallel builds and mirrors reduce build times and improve developer productivity, especially in large projects.

CI/CD Integration Note

Integrating Maven into CI/CD pipelines automates testing, building, and deployment processes, minimizing manual intervention and errors. Tools like Jenkins, GitHub Actions, and GitLab CI can invoke Maven commands to ensure code quality and consistent releases.

Parallel Build Optimization Note

Leveraging Maven’s parallel build capabilities (-T) helps utilize system resources efficiently, reducing build times. However, not all Maven plugins support parallel execution, so testing is essential before enabling it in production pipelines.

Infrastructure as Code: Ansible Playbook (Ubuntu)

Use this ready-to-run Ansible playbook to install OpenJDK 17+ and Apache Maven from the official Ubuntu repositories. It is idempotent (safe to re-run), contains explanatory comments, and triggers a handler to verify mvn -version at the end. This is designed for team-scale, repeatable installs.

- name: Install Java 17+ and Apache Maven on Ubuntu
  hosts: maven_hosts            # Define your inventory group
  become: true                  # Elevate privileges for package installs
  gather_facts: true

  vars:
    java_package: openjdk-17-jdk

  pre_tasks:
    # Ensure apt metadata is fresh; prevents 404 errors and pulls security updates
    - name: Update apt cache
      ansible.builtin.apt:
        update_cache: true
        cache_valid_time: 3600

  tasks:
    # 1) Ensure a compatible JDK (>= 17) exists. This will not downgrade newer JDKs.
    - name: Ensure OpenJDK 17+ is installed (idempotent)
      ansible.builtin.apt:
        name: "{{ java_package }}"
        state: present

    # 2) Install Maven from Ubuntu repositories for stability and OS integration
    - name: Ensure Apache Maven is installed from Ubuntu repo (idempotent)
      ansible.builtin.apt:
        name: maven
        state: present
      notify: Verify Maven installation

    # 3) Optionally verify mvn is discoverable on PATH for non-login shells
    - name: Check Maven is on PATH
      ansible.builtin.command: bash -lc 'command -v mvn'
      register: mvn_path
      changed_when: false

    # 4) Flush handlers so verification runs within the same play
    - name: Flush handlers to verify installation now
      ansible.builtin.meta: flush_handlers

  handlers:
    # Handler runs only when Maven installation task reports a change.
    - name: Verify Maven installation
      listen: Verify Maven installation
      ansible.builtin.command: mvn -version
      register: mvn_version
      changed_when: false
      failed_when: mvn_version.rc != 0

    - name: Output Maven version
      listen: Verify Maven installation
      ansible.builtin.debug:
        msg: "{{ mvn_version.stdout | default(mvn_version.stderr) }}"

AI-Powered Maven Workflows and Use Cases (In-Depth)

Installing Maven is table stakes. The real leverage comes from pairing Maven with AI to automate configuration, speed up CI/CD, harden security, and reduce mean time to green. The patterns below are implementation-grade: prompt ideas, exact commands, and “why it matters” so readers can copy-paste with confidence and understand the tradeoffs.

  1. AI-Generated pom.xml with Guardrails (Reproducible, Policy-Aware)

Answer: Use an LLM to draft/refactor pom.xml that enforces org policy (Java toolchain, reproducible builds, plugin baselines), then validate with Enforcer. How:

Prompt an LLM to create pom.xml with:

pluginManagement (surefire, failsafe, compiler with release 17/21),

Maven Enforcer rules (min Java, banned deps),

Reproducible builds (deterministic jars, timestamps).

Validate locally:

mvn -q -DskipTests dependency:resolve enforcer:enforce
mvn -q help:effective-pom > effective-pom.xml

Feed any Enforcer failures back to the LLM for a revised pom.xml. Why it matters: You codify standards on day one, avoid drift, and ship a stable baseline that scales across teams.

  1. AI-Assisted Dependency Conflict Resolution (Stop “Tree-Gazing”)

Answer: Generate a dependency tree, let AI propose the minimal dependencyManagement pin set, then re-verify. How:

mvn -q dependency:tree -Dscope=compile > deps.txt
mvn -q versions:use-latest-releases -DgenerateBackupPoms=false -DdryRun > versions.txt

Ask an LLM:

From deps.txt + versions.txt, propose a minimal dependencyManagement block to resolve conflicts and justify each version.

Apply the suggested block, then:

mvn -q -DskipTests dependency:resolve

Why it matters: Faster conflict triage, fewer risky upgrades, clearer justifications for code review.

  1. LLM-Generated CI/CD for Maven (Matrix, Cache, Test Reports, Signing)

Answer: Have an LLM author a best-practice pipeline with JDK matrix, Maven cache, test reports, and optional signing/publish. GitHub Actions example:

name: Maven Build
on: [push, pull_request]
jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        java: [17, 21]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-java@v4
        with:
          distribution: temurin
          java-version: ${{ matrix.java }}
          cache: maven
      - name: Build & Test
        run: mvn -B -U clean verify
      - name: Upload Test Reports
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: surefire-reports
          path: '**/target/surefire-reports/*.xml'

Why it matters: Consistency across environments, faster builds, and visibility into failures.

  1. AI-Powered Install Automation (Idempotent Bash, cloud-init, Ansible)

Answer: Ask an LLM for an idempotent installer that detects Ubuntu version, ensures JDK, installs Maven, exports env vars, and self-verifies. Bash skeleton (idempotent):

#!/usr/bin/env bash
set -euo pipefail
if ! command -v mvn >/dev/null 2>&1; then
  sudo apt-get update -y
  sudo apt-get install -y openjdk-21-jdk maven
fi
mvn -version

cloud-init (for droplets/VMs):

#cloud-config
packages: [openjdk-21-jdk, maven]
runcmd: [ "mvn -version" ]

Why it matters: Repeatable, auditable installs that plug into CI, golden images, and autoscaling workflows.

  1. Security: OWASP + SBOM + AI Triage (Real-World Risk Reduction)

Answer: Generate a vulnerability report and SBOM; have AI prioritize fixes by exploitability/impact and propose safe ranges. How:

# OWASP Dependency-Check
mvn org.owasp:dependency-check-maven:check -Dformat=JSON -Doutput=dc.json

# CycloneDX SBOM
mvn org.cyclonedx:cyclonedx-maven-plugin:makeAggregateBom -Dcyclonedx.output.format=json

Tip: Use -B (batch mode) with Maven in automation scripts to ensure non-interactive builds: mvn -B clean install.

Prompt:

From dc.json + SBOM, group CVEs by severity and known exploits, propose minimal upgrades, note breaking changes.

Why it matters: Converts raw scanner noise into actionable upgrades and review-ready PR notes.

  1. Log-Driven Troubleshooting with AI (Surefire/Enforcer/JAVA_HOME)

Answer: Pipe failing logs to an LLM to classify root cause (config, env, flaky test) and return exact patch steps. How:

mvn -B clean verify 2> build.log || true

Prompt:

Classify root cause from build.log + surefire-reports, propose minimal diffs and env fixes.

Why it matters: Cuts mean time to green; better than generic “try -X” advice since it returns precise diffs and env fixes.

  1. Release Notes & Versioning, Auto-Drafted by AI (Conventional Commits)

Answer: Use Conventional Commits and have AI draft human-grade release notes from commit history and test reports. How:

After mvn verify, collect commits since last tag; ask the LLM for a CHANGELOG with breaking changes, features, fixes, PR links, Java compatibility notes.

Publish as CHANGELOG.md and GitHub Release body. Why it matters: Clean release hygiene, less PM time, better consumer transparency.

AI Workflows: Install & Automate Maven

Example LLM Prompt: Generate an Idempotent Maven Install Script (Ubuntu)

You are a senior DevOps engineer. Write an idempotent bash script for Ubuntu 22.04/24.04 that:
- Ensures OpenJDK 17+ and Maven are installed using apt if not present
- Exports JAVA_HOME and ensures mvn is on PATH for login shells
- Is safe to re-run and exits on errors
- Prints `java -version` and `mvn -version` for validation at the end
Constraints:
- Non-interactive; suitable for CI
- Use set -euo pipefail
- Detect existing installs without reinstalling
Output only a single bash script in a code block.

Annotated Output Script + Validation

#!/usr/bin/env bash
set -euo pipefail
# Detect distro (Ubuntu) and refresh apt metadata once
if ! command -v lsb_release >/dev/null 2>&1; then sudo apt-get update -y; fi
sudo apt-get update -y
# Ensure JDK 17+ is present (idempotent)
if ! command -v java >/dev/null 2>&1; then
  sudo apt-get install -y openjdk-17-jdk
fi
# Ensure Maven is present (idempotent)
if ! command -v mvn >/dev/null 2>&1; then
  sudo apt-get install -y maven
fi
# Export JAVA_HOME for current shell and future logins (user-scoped)
JAVA_BIN_PATH="$(readlink -f "$(command -v java)")"
JAVA_HOME_CANDIDATE="${JAVA_BIN_PATH%/bin/java}"
if [ -d "$JAVA_HOME_CANDIDATE" ]; then
  export JAVA_HOME="$JAVA_HOME_CANDIDATE"
fi

PROFILE_FILE="$HOME/.profile"
if ! grep -q "JAVA_HOME" "$PROFILE_FILE" 2>/dev/null; then
  {
    echo "export JAVA_HOME=$JAVA_HOME"
    echo 'export PATH="$JAVA_HOME/bin:$PATH"'
  } >> "$PROFILE_FILE"
fi
# Quick validation
java -version
mvn -version

Validation steps:

  • Run the script and ensure both commands return expected versions:
    • java -version should show 17+.
    • mvn -version should show Maven with the Java runtime path.
  • Open a new shell and re-run mvn -version to confirm PATH/JAVA_HOME persistence.

Terraform, Ansible, and cloud-init Snippets

Terraform (DigitalOcean Droplet with cloud-init)

provider "digitalocean" {}

resource "digitalocean_droplet" "maven_host" {
  name = "maven-ubuntu"
  region = "nyc3"
  size = "s-1vcpu-1gb"
  image = "ubuntu-24-04-x64"
  ssh_keys = [var.ssh_key_fingerprint]
  user_data = file("cloud-init-maven.yaml")
  backups = false
  monitoring = true
  ipv6 = true
}

cloud-init (Installs OpenJDK 17+ and Maven, validates)

#cloud-config
package_update: true
packages:
  - openjdk-17-jdk
  - maven
runcmd:
  - [ bash, -lc, "java -version" ]
  - [ bash, -lc, "mvn -version" ]

Ansible (Minimal, idempotent)

- name: Ensure Java 17+ and Maven on Ubuntu
  hosts: all
  become: true
  tasks:
    - name: Install OpenJDK 17+
      ansible.builtin.apt:
        name: openjdk-17-jdk
        state: present
        update_cache: true

    - name: Install Maven
      ansible.builtin.apt:
        name: maven
        state: present

    - name: Validate Java and Maven
      ansible.builtin.shell: |
        set -euo pipefail
        java -version
        mvn -version
      args:
        executable: /bin/bash
      register: validate_out
      changed_when: false

Frequently Asked Questions

Should I install Maven via apt, SDKMAN, or manual binaries for production and CI/CD?

While apt is convenient, Ubuntu repositories often provide outdated Maven versions, which may lack critical features or compatibility with newer Java releases. For production, CI/CD, or when you need to pin or upgrade Maven versions reliably, prefer SDKMAN or manual binary installation. SDKMAN is scriptable and supports version switching, making it ideal for automation and reproducibility.

Pro Tip: Always verify the installed Maven version with mvn -version in your automation scripts to avoid unexpected mismatches.

How do I ensure Maven uses the correct Java version, especially with multiple JDKs installed?

Maven relies on the JAVA_HOME environment variable to locate the JDK. If multiple JDKs are present, explicitly set JAVA_HOME in your shell profile, CI/CD pipeline, or Dockerfile. For multi-user or multi-project systems, tools like jEnv or SDKMAN can help manage and switch Java versions per shell or project.

How do I upgrade or switch between Maven versions safely?

  • SDKMAN: Use sdk install maven <version> or sdk use maven <version> to switch versions per shell or script.
  • Manual: Download the desired Maven binary, update M2_HOME and your PATH, and remove or archive the old version.
  • Automated Environments: Pin the Maven version in your Dockerfile, Ansible playbook, or CI/CD config for reproducibility.

Edge Case: If you have system-wide and user-specific Maven installations, ensure your PATH prioritizes the intended version.

Why are JAVA_HOME and M2_HOME important, and how do I set them for all users or automation?

  • JAVA_HOME: Required for Maven to find the Java compiler and runtime. Set it explicitly to avoid picking up the wrong Java version.
  • M2_HOME: Points to your Maven installation directory. Not always required, but recommended for clarity, especially with multiple Maven versions.
  • PATH: Ensure both $JAVA_HOME/bin and $M2_HOME/bin are in your PATH.

For system-wide settings, add these to /etc/profile.d/ scripts. For user-specific or CI/CD, set them in .bashrc, .profile, or your pipeline config.

How can I automate Java and Maven installation across multiple servers or CI agents?

Use configuration management tools like Ansible, Chef, or Puppet to script installation and environment variable setup. For containers, define installation steps in your Dockerfile. SDKMAN supports non-interactive installation (sdk install maven <version> -y), making it suitable for automation.

How do I configure Maven for enterprise use (mirrors, proxies, and private repositories)?

Edit your ~/.m2/settings.xml (or global /etc/maven/settings.xml) to:

  • Define <mirrors> for faster or internal artifact resolution.
  • Set up <proxies> for environments behind corporate firewalls.
  • Add <servers> for authentication to private repositories (e.g., Nexus, Artifactory).

For reproducible builds, version-control a custom settings.xml and reference it with mvn -s <path> in your CI/CD scripts.

How do I optimize Maven builds for large projects or CI/CD pipelines?

  • Use parallel builds: mvn -T 1C clean install (one thread per CPU core).
  • Enable build caching with Maven Build Cache Extension.
  • Configure dependency mirrors close to your build agents.
  • Use the --fail-fast or --fail-at-end flags for better error handling in multi-module projects.

How do I debug Maven build failures in automated environments?

  • Run with -X for full debug output: mvn -X clean install.
  • Check for environment variable mismatches (JAVA_HOME, M2_HOME, PATH).
  • Inspect settings.xml for misconfigured repositories or proxies.
  • Clear the local repository cache: rm -rf ~/.m2/repository.
  • Compare java -version and mvn -version outputs to ensure alignment.

How do I uninstall Maven?

  • If installed via APT:

    sudo apt remove maven
    

    Optionally, remove configuration and cache:

    rm -rf ~/.m2
    
  • If installed from a tarball or binary:

    sudo rm -rf /opt/apache-maven-3.9.9
    

    Remove any related environment variable lines from your ~/.profile or ~/.bashrc.

Where is Maven installed on Ubuntu?

  • To find the location of the mvn binary:

    which mvn
    
  • To list all files installed by the APT package:

    dpkg -L maven
    
  • To see the actual path of the Maven binary:

    readlink -f $(which mvn)
    

Conclusion

You have successfully installed Apache Maven on your Linux (Ubuntu) system using your preferred method. Maven is now ready to build and manage your Java projects efficiently. For advanced usage and automation, consider integrating Maven into your CI/CD pipelines. To learn more about deploying your Maven-based applications, explore How To Deploy to DigitalOcean App Platform. Happy coding!

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the author(s)

Pankaj Kumar
Pankaj Kumar
Author
See author profile

Java and Python Developer for 20+ years, Open Source Enthusiast, Founder of https://www.askpython.com/, https://www.linuxfordevices.com/, and JournalDev.com (acquired by DigitalOcean). Passionate about writing technical articles and sharing knowledge with others. Love Java, Python, Unix and related technologies. Follow my X @PankajWebDev

Vinayak Baranwal
Vinayak Baranwal
Editor
See author profile

Building future-ready infrastructure with Linux, Cloud, and DevOps. Full Stack Developer & System Administrator @ DigitalOcean | GitHub Contributor | Passionate about Docker, PostgreSQL, and Open Source | Exploring NLP & AI-TensorFlow | Nailed over 50+ deployments across production environments.

Still looking for an answer?

Was this helpful?

very helpful and genuine tutorial simply i love it.

- tabitha

The current Linux x86 JDK is 15.0.1. During the command, tar -xvf openjdk-13.0.1_linux-x64_bin.tar.gz: there is openjdk-13.0.1, but the current JDK requires the modified command, openjdk-15.0.1.

- Jonathan M. Kelly

Very helpful tutorial. It worked the first time like charm. Many Thanks!!

- Sanjay Ghosh

no words super

- srikanth

Excuse me, where to find the user profile file? Cannot find it anywhere. Thanks, kr, Yannick

- Yannick Mussche

Creative CommonsThis work is licensed under a Creative Commons Attribution-NonCommercial- ShareAlike 4.0 International License.
Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

The developer cloud

Scale up as you grow — whether you're running one virtual machine or ten thousand.

Get started for free

Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

*This promotional offer applies to new accounts only.