Installing SonarQube on Linux and Ubuntu

Installing SonarQube on Linux and Ubuntu

Installing SonarQube on Linux or Ubuntu is one of those jobs that looks simple on paper and then quietly teaches you a lot about Java, databases, Linux services, and server tuning. That is not a bad thing. In fact, that is part of why SonarQube is such a useful tool: it sits close to your code, but it also reminds you that a healthy software platform depends on a healthy machine, a sane database, and a well-behaved service manager. The current SonarQube Server documentation says Linux is supported on x64 and AArch64, and for ZIP-based server installations the runtime now requires JDK 21 or JDK 25; Java 17 is no longer the right choice for the current server runtime.

When people say “install SonarQube on Ubuntu,” they often mean they want the cleanest possible path from a blank server to a working dashboard on port 9000. That path usually involves four parts: a supported JDK, an external database such as PostgreSQL, a properly tuned Linux host, and either a manual startup or a systemd service so the server survives reboots. SonarSource’s current docs recommend a supported external database for production, note that the embedded H2 database is only for tests, and describe the Linux host limits that must be in place for Elasticsearch to behave correctly.

A lot of guides on the internet still use old Java versions or skip the Linux tuning steps completely. That is where trouble starts. SonarQube’s embedded Elasticsearch expects a host that can handle memory-mapped files, file descriptors, and enough process threads. The official Linux pre-installation page gives concrete minimums: vm.max_map_count at least 524288, fs.file-max at least 131072, user file descriptors at least 131072, and user threads at least 8192. It also notes that Elasticsearch 8.x needs writable access to /tmp.

Before you install anything, decide how you want to run SonarQube

The safest way to approach SonarQube on Ubuntu is to think in layers. First, decide whether the instance is for a quick test or for real team use. Second, decide whether the database will live on the same machine or a different one. Third, decide whether you want to start SonarQube manually or register it as a systemd service. Fourth, decide whether you are installing from the ZIP distribution or using Docker. The official docs cover both ZIP and Docker, but for a hands-on Linux install, the ZIP method is still the best way to understand what is happening under the hood.

For production, SonarSource recommends hosting the database on a separate machine with low latency to the SonarQube server, and it explicitly says not to use the embedded H2 database in production. Current database support for SonarQube Server 2026.1 LTA includes PostgreSQL 14 through 18, along with supported Microsoft SQL Server and Oracle versions. If you are following an older article that tells you to use PostgreSQL 11 or 12, that guide is stale.

For a smaller installation, the current host recommendations are more forgiving than many people expect, but still serious enough to matter. SonarSource’s current server-host requirements list 4 GB RAM, 2 CPU cores, 30 GB disk, and at least 10% free disk space for a small-scale installation, with larger installations needing more. Those numbers are a starting point, not magic. If your repository count, background tasks, or analysis volume grows, you will feel it in CPU, memory, and disk I/O before you feel it anywhere else.

What you need on Ubuntu

Here is the practical shopping list for a clean Ubuntu install:

You need a supported JDK for the SonarQube server itself, and the current SonarQube Server docs call for JDK 21 or 25 for ZIP-based installations. You need a supported database, and the current LTA docs support PostgreSQL 14 through 18. You need enough RAM and disk to keep Elasticsearch comfortable, plus the Linux host settings that let Elasticsearch create files and memory maps without hitting kernel limits. You also need a dedicated user account, because SonarQube must not run as root.

A simple Ubuntu preparation command set usually looks like this:

sudo apt update
sudo apt install -y openjdk-21-jdk unzip wget curl gnupg ca-certificates postgresql postgresql-contrib
java -version
psql --version

That command set is an example, not a SonarSource-specific prescription. The key requirement is that the server ends up on a supported JDK and a supported PostgreSQL release, with the JDK version matching the current SonarQube Server runtime requirement.

If you are on a fresh Ubuntu server, it is also worth checking the machine itself before you install anything. free -h, df -h, and nproc are the fastest reality checks in the world. They tell you whether you are about to install a code-quality server on a machine that can actually breathe. That sounds obvious until the first indexing job lands and the machine starts swapping like a forgotten laptop from 2016.

Prepare the Linux host properly

This is the step that gets skipped the most and causes the most quiet pain later. SonarQube uses Elasticsearch internally, and SonarSource’s Linux pre-installation guidance says the host must comply with Elasticsearch production-mode expectations and file-descriptor requirements. In practice, that means adjusting kernel limits and user limits before you start the service.

The official minimums are clear, so use them as your baseline:

sudo tee /etc/sysctl.d/99-sonarqube.conf > /dev/null <<'EOF'
vm.max_map_count=524288
fs.file-max=131072
EOF

sudo sysctl --system

Then set user limits for the dedicated SonarQube account:

sudo tee /etc/security/limits.d/99-sonarqube.conf > /dev/null <<'EOF'
sonarqube   -   nofile   131072
sonarqube   -   nproc    8192
EOF

For a systemd-managed service, the docs say you can also define those values inside the unit file under [Service]. The important thing is not the placement; the important thing is that the limits actually apply to the process that runs SonarQube.

A few more host details matter more than they seem at first glance. SonarSource notes that Elasticsearch uses seccomp filtering, so the kernel should support seccomp. It also notes that /tmp must be writable because Elasticsearch 8.x requires read and write access there. If your host uses read-only filesystem policies, you need to provide a writable /tmp path or the service will fail in unpleasant ways.

If you are using Ubuntu and a separate firewall layer, remember that SonarQube listens on port 9000 by default. The docs say the default web port is 9000 and the server is reachable at http://localhost:9000 after a successful start. That means your local tests should work immediately, but remote access may still need firewall or reverse-proxy rules.

Set up PostgreSQL the right way

For real use, PostgreSQL is the most common choice on Linux and Ubuntu. The current SonarQube documentation supports PostgreSQL 14 through 18 for the 2026.1 LTA line, recommends a separate database host for production, That is a very sensible split: lightweight local testing is fine, but production needs a database that is stable, backed up, and predictable.

Here is a straightforward PostgreSQL setup pattern on Ubuntu:

sudo -u postgres psql

Inside psql, create the database and user:

CREATE USER sonarqube WITH ENCRYPTED PASSWORD 'StrongPasswordHere';
CREATE DATABASE sonarqube OWNER sonarqube;
GRANT ALL PRIVILEGES ON DATABASE sonarqube TO sonarqube;
\q

SonarSource’s docs also say to create or use an empty schema, grant the SonarQube user create, update, and delete permissions on that schema, and then configure the database access in sonar.properties. The current ZIP installation example for PostgreSQL uses a JDBC URL like jdbc:postgresql://localhost/sonarqube.

If your PostgreSQL server is on another host, keep the latency low and make sure the network path is stable. SonarQube is happiest when the database feels local even if it is not physically local. That recommendation is not just about performance; it is also about reducing the amount of failure surface between the application server and the database.

Download and unpack SonarQube

The current ZIP installation docs say to download the distribution, unzip it into a directory that does not start with a digit, and treat that extracted folder as your <sonarqubeHome>. They also say SonarQube cannot run as root on Unix-based systems, so you should create a dedicated user account if needed.

A clean installation layout on Ubuntu might look like this:

sudo useradd --system --create-home --shell /bin/bash sonarqube
sudo mkdir -p /opt/sonarqube
sudo chown -R sonarqube:sonarqube /opt/sonarqube

Then download the ZIP distribution from the official SonarSource release page, place it in a temporary location, and unpack it:

cd /tmp
wget <official-sonarqube-zip-url>
sudo unzip sonarqube-*.zip -d /opt
sudo mv /opt/sonarqube-* /opt/sonarqube
sudo chown -R sonarqube:sonarqube /opt/sonarqube

The exact filename changes with each release, so that mv line is intentionally written as a pattern. What matters is that the final directory is owned by the sonarqube user and contains the SonarQube distribution tree. SonarSource also notes that the JDBC drivers for supported databases are already bundled, except for Oracle, and that the bundled drivers should not be replaced.

One detail that is easy to miss: when you upgrade later, the sonar-application JAR name changes with the version, and the service definition may need to be updated accordingly. SonarSource calls that out directly in its systemd guidance. That is one reason some administrators prefer to keep their install path and service file tidy from day one instead of improvising at the end.

Configure sonar.properties

Now the installation becomes more personal. This is the file where SonarQube learns how to talk to the database, where to store data, and how to behave at startup. The official ZIP guide says to edit <sonarqubeHome>/conf/sonar.properties, uncomment the template for your database, and comment out the H2 lines. For PostgreSQL, the sample settings include the username, password, and JDBC URL.

A practical PostgreSQL block looks like this:

sonar.jdbc.username=sonarqube
sonar.jdbc.password=StrongPasswordHere
sonar.jdbc.url=jdbc:postgresql://localhost/sonarqube

If you later move PostgreSQL to a different machine, only the JDBC URL usually changes. The rest of the application remains the same, which is one of the nicer things about keeping the application and database concerns separate. SonarSource’s docs also say the database host should ideally be separate from the SonarQube host in production.

You should also pay attention to Elasticsearch storage. SonarSource says the default Elasticsearch data location is <sonarqubeHome>/data, but that is not recommended for production. Instead, store it elsewhere, ideally on a dedicated volume with fast I/O, and make sure the SonarQube user has read and write access to those directories.

Here is a pattern many Linux admins use:

sudo mkdir -p /var/sonarqube/{data,extensions,logs}
sudo chown -R sonarqube:sonarqube /var/sonarqube

Then in sonar.properties, point the data and temp-related paths to those locations if needed by your edition and setup. The idea is simple: keep the application binaries under /opt, and keep mutable data on a volume designed for writes. It makes upgrades easier and backups less confusing.

Start SonarQube for the first time

SonarSource documents two common ways to start the server from a ZIP install. For a manual start on Linux, the script is <sonarqubeHome>/bin/linux-x86-64/sonar.sh start. Once the server has started successfully, you can open SonarQube in your browser at http://localhost:9000, and the default administrator credentials are admin / admin.

The first startup is usually the moment when people discover whether all the earlier prep was worth it. If the Java version is wrong, the host limits are too low, or the database settings are incomplete, the server will tell you. That is not SonarQube being difficult; that is SonarQube being honest. It tends to fail where the environment is weak rather than hiding the problem for later.

A clean startup check looks like this:

sudo -u sonarqube /opt/sonarqube/bin/linux-x86-64/sonar.sh start
sudo -u sonarqube /opt/sonarqube/bin/linux-x86-64/sonar.sh status

If you prefer to watch logs directly, open the SonarQube log directory and look at the web and Elasticsearch logs:

sudo tail -f /opt/sonarqube/logs/sonar.log
sudo tail -f /opt/sonarqube/logs/web.log
sudo tail -f /opt/sonarqube/logs/es.log

The exact log file names may vary a little by version, but the principle does not change: when startup fails, logs are your map.

Turn it into a proper systemd service

Manual starts are fine for experiments, but a real Ubuntu server should run SonarQube as a service. SonarSource’s systemd documentation says you can install SonarQube as a service on Unix-like systems using systemd, that SonarQube must not run as root, and that all SonarQube directories should be owned by the sonarqube user. It also warns that the ExecStart command may need adjustment at each upgrade because the JAR filename includes the SonarQube version.

A service file can look like this:

[Unit]
Description=SonarQube service
After=network.target

[Service]
Type=simple
User=sonarqube
Group=sonarqube
PermissionsStartOnly=true
ExecStart=/opt/java/bin/java -Xms32m -Xmx32m -Djava.net.preferIPv4Stack=true -jar /opt/sonarqube/lib/sonar-application-2026.1.0.119033.jar
LimitNOFILE=131072
LimitNPROC=8192
Restart=always
SuccessExitStatus=143

[Install]
WantedBy=multi-user.target

Then enable and start it:

sudo systemctl daemon-reload
sudo systemctl enable sonarqube
sudo systemctl start sonarqube
sudo systemctl status sonarqube

The service example above mirrors the shape of SonarSource’s systemd guidance: dedicated user, dedicated group, explicit limits, and a Java command that points to the versioned SonarQube application JAR. If you upgrade SonarQube later, remember that the JAR name usually changes and the unit file should be updated accordingly.

There is also a nice operational benefit to systemd that people underestimate: it gives you one place to check whether the server died, restarted, or failed to bind. That matters when a code quality tool becomes part of a team’s daily workflow. You do not want to guess whether the dashboard is unavailable because the network is broken or because the service never came up.

A minimal Ubuntu hardening pass

Once SonarQube is running, do not stop at “it works.” A good Linux install should also survive ordinary life: reboots, package updates, log growth, and the occasional bad deploy. Start with permissions. SonarQube should belong to the sonarqube user, not to root, and the data directories should be writable only by the processes that need them. SonarSource is explicit about not running SonarQube as root and about giving the service user ownership of SonarQube directories.

Next, think about storage. SonarSource recommends a dedicated volume with fast I/O for Elasticsearch data because the index data sees a lot of read/write activity. That is not a detail for huge enterprises only. Even a small team can notice the difference between “data on a slow disk” and “data on a proper volume” the first time background analysis runs during office hours.

Then think about ports and access. The default web port is 9000. On a single-server setup you can keep it local at first, but in a real environment you will often place it behind a reverse proxy or a load balancer. SonarSource’s docs expose the web port as 9000 and describe web connection configuration in the advanced installation material.

If you are using Ubuntu’s firewall, the kind of command you might use is this:

sudo ufw allow 9000/tcp
sudo ufw reload

That is not an official SonarQube command. It is simply the kind of ordinary Ubuntu step that helps make the official port settings usable on a real machine.

How to check that everything is healthy

A good SonarQube install should be boring after the first successful launch. You should be able to reach the dashboard, log in, and see the main interface without guessing. SonarSource says the successful startup message appears in the console output or logs, and after that you can browse to the configured address, which is http://localhost:9000 by default.

A quick checklist helps:

systemctl status sonarqube
ss -ltnp | grep 9000
ps aux | grep sonar

Those commands are standard Linux diagnostics. They tell you whether the service is active, whether the port is open, and whether the expected Java process is actually present.

If the server starts but the browser never loads, the issue is often one of three things: the service is bound only to localhost, the firewall blocks port 9000, or the server has started but is still initializing. SonarQube is not instant on first boot, especially when Elasticsearch and the database need a moment to settle. Patience is normal here. Panic usually is not.

If the browser opens and the login screen appears, the default credentials are admin and admin. Change them immediately. That is not just a best practice; it is the kind of habit that keeps a lab setup from accidentally behaving like a production account.

Troubleshooting the problems that most often show up

The most common early failure is a Java mismatch. The current SonarQube Server ZIP installation docs require Java 21 or 25, and the 2026.1 LTA notes say the server runtime now requires a full JDK rather than just a JRE. If you accidentally install the wrong major version, SonarQube will usually make that obvious in the logs.

The second common issue is database configuration. If the JDBC URL, username, password, or database privileges are wrong, the server may start partially and then fail while trying to connect. SonarSource’s database documentation tells you to create an empty schema, give the SonarQube user the needed permissions, and use one of the supported engines. For PostgreSQL, the current supported range is 14 to 18.

The third issue is Linux limits. If vm.max_map_count, fs.file-max, nofile, or nproc are too low, Elasticsearch can refuse to come up correctly. SonarSource’s Linux page gives the exact values to set, and it also reminds you that the user running SonarQube needs access to enough threads and file descriptors. That is why the tuning step near the beginning matters so much.

The fourth issue is filesystem layout. If SonarQube’s data or logs live in the wrong place, or if the service user cannot write to the required directories, startup may fail in a way that looks mysterious but is actually simple. The cure is always the same: read the logs, confirm ownership, confirm permissions, and confirm that the filesystem is writable where SonarQube expects it to be. SonarSource’s docs explicitly say the user launching SonarQube must have read and write access to the configured directories.

Here is a tiny mental model that helps during debugging: if the problem is early, think Java or permissions; if the problem is after startup, think database or Elasticsearch; if the problem is in the browser, think port, proxy, or firewall. That is not an official checklist, just a practical one built from how these installations usually fail in the real world.

A clean example from start to finish

This compact example brings the main pieces together. It assumes Ubuntu, a dedicated sonarqube user, PostgreSQL on the same machine, and a ZIP-based install using the current JDK requirement. The commands are illustrative, but the requirements they satisfy come from the official documentation.

# 1) Install dependencies
sudo apt update
sudo apt install -y openjdk-21-jdk unzip wget curl postgresql postgresql-contrib

# 2) Create service user and directories
sudo useradd --system --create-home --shell /bin/bash sonarqube
sudo mkdir -p /opt/sonarqube /var/sonarqube/{data,extensions,logs}
sudo chown -R sonarqube:sonarqube /opt/sonarqube /var/sonarqube

# 3) Configure kernel tuning
sudo tee /etc/sysctl.d/99-sonarqube.conf > /dev/null <<'EOF'
vm.max_map_count=524288
fs.file-max=131072
EOF
sudo sysctl --system

# 4) Create PostgreSQL database
sudo -u postgres psql <<'SQL'
CREATE USER sonarqube WITH ENCRYPTED PASSWORD 'StrongPasswordHere';
CREATE DATABASE sonarqube OWNER sonarqube;
GRANT ALL PRIVILEGES ON DATABASE sonarqube TO sonarqube;
SQL

# 5) Download and unpack SonarQube
cd /tmp
wget <official-sonarqube-zip-url>
sudo unzip sonarqube-*.zip -d /opt
sudo mv /opt/sonarqube-* /opt/sonarqube
sudo chown -R sonarqube:sonarqube /opt/sonarqube

# 6) Configure sonar.properties
sudo nano /opt/sonarqube/conf/sonar.properties

# 7) Start the server
sudo -u sonarqube /opt/sonarqube/bin/linux-x86-64/sonar.sh start

After that, open http://localhost:9000, log in with admin/admin, and change the password immediately. If you are turning this into a long-lived server, register it as a systemd service instead of relying on manual starts.

A few closing thoughts

A SonarQube install on Linux or Ubuntu is rarely just “install the app.” It is really a small exercise in setting up a healthy service platform: the right JDK, the right database, the right limits, the right ownership, and the right startup method. The current official docs are actually very clear once you follow them in order: check host requirements, tune the Linux host, install the database, unpack the ZIP, configure sonar.properties, and start the service.

#SonarQube #SonarQube Linux installation #SonarQube Ubuntu #SonarQube Server #install SonarQube on Ubuntu #SonarQube PostgreSQL #SonarQube systemd #Linux code quality #Java 21 SonarQube #SonarQube tutorial

Subscribe to our newsletter

12k+

Subscribers

Weekly

Frequency

Free

Always