Introduction
In a previous post,
I showed how to install Gerrit 3.11.2 on Ubuntu 24.04 with:
- Java 21
- A dedicated
gerritsystem user - Embedded Jetty + H2 database
- A
systemdservice
After that, I upgraded my lab instance offline to Gerrit 3.12.2 (not documented).
This post starts from a working Gerrit 3.12.2 instance and shows how to upgrade it to Gerrit 3.13.1 on the same server, using the offline upgrade method.
Key points for 3.12 → 3.13:
- No schema change
- No reindex needed
- Single-node upgrade is basically:
stop Gerrit → replacegerrit.war→ update plugins → start Gerrit
Offline vs Zero-Downtime Upgrade
Gerrit 3.13 supports two upgrade paths.
Offline upgrade (what this post uses)
Use this for single-node Gerrit or when you can afford a short outage:
- Stop Gerrit.
- Download the new
gerrit.warand move it to$GERRIT_SITE/bin. - Extract plugins from the new WAR and copy the ones you need into
$GERRIT_SITE/plugins. - Start Gerrit again.
This is what I do in this post.
Zero-downtime upgrade (HA only)
If you run multiple Gerrit nodes in a high-availability setup:
- Start with Gerrit 3.12 on all nodes, healthy, behind a load balancer.
- Mark one node unhealthy so it stops receiving traffic.
- Stop that node, update
gerrit.war, plugins, and libs to 3.13.x, then start it. - Run smoke tests, mark the node healthy again, and let it catch up with missed events.
- Repeat for the remaining nodes, one by one.
My lab is single-node, so I only use the offline path.
Lab Overview
At the start of this post my environment is:
- Gerrit version: 3.12.2
- Target version: 3.13.1
- OS: Ubuntu 24.04
- Java: OpenJDK 21 (
openjdk-21-jdk) - Gerrit site path (
$GERRIT_SITE):/srv/gerrit - System user:
gerrit - Database: Embedded H2
- Public URL:
https://gerrit.maksonlee.com/ - Auth:
auth.type = OAUTHvia Keycloak (https://keycloak.maksonlee.com, realmmaksonlee.com) - Reverse proxy: HAProxy with TLS termination, forwarding HTTPS
:443→ Gerrit on127.0.0.1:8080
systemd unit:
# /etc/systemd/system/gerrit.service
[Unit]
Description=Gerrit Code Review
After=network.target
[Service]
Type=simple
LimitNOFILE=65536
User=gerrit
ExecStart=/usr/bin/java -jar /srv/gerrit/bin/gerrit.war daemon -d /srv/gerrit
RemainAfterExit=yes
Restart=on-failure
OOMScoreAdjust=-1000
[Install]
WantedBy=multi-user.target
Key parts of gerrit.config:
# /srv/gerrit/etc/gerrit.config
[gerrit]
basePath = git
canonicalWebUrl = https://gerrit.maksonlee.com/
[container]
user = gerrit
javaHome = /usr/lib/jvm/java-21-openjdk-amd64
[index]
type = lucene
[auth]
type = OAUTH
userNameCaseInsensitive = true
gitBasicAuthPolicy = HTTP
[httpd]
listenUrl = proxy-https://127.0.0.1:8080/
[sshd]
listenAddress = *:29418
[cache]
directory = cache
[plugins]
allowRemoteAdmin = true
[plugin "gerrit-oauth-provider-keycloak-oauth"]
client-id = gerrit
root-url = https://keycloak.maksonlee.com
realm = maksonlee.com
My plugins directory before upgrade looks like:
checks-jenkins.jar # external (Jenkins Checks integration)
codemirror-editor.jar # core
delete-project.jar # core
download-commands.jar # core
events-log.jar # external (Gerrit-CI plugin)
gitiles.jar # core
oauth.jar # external (gerrit-oauth)
plugin-manager.jar # core
reflog-recorder-1.0.0.jar # external/custom
replication.jar # core
If your 3.12.2 instance is similar, you can follow the same steps.
- Confirm You’re on 3.12.2
Check the current version:
sudo -u gerrit java -jar /srv/gerrit/bin/gerrit.war version
You should see:
gerrit version 3.12.2
Also check the service status:
sudo systemctl status gerrit
If it’s active (running) and logs look normal, you’re ready.
- Stop Gerrit
Before touching anything under /srv/gerrit, stop the daemon.
sudo systemctl stop gerrit
sudo systemctl status gerrit
Make sure it is actually stopped (not running or activating) before continuing.
- Back Up Site + Meta Repos (Skip Project Repos)
I keep large codebases (like AOSP) inside /srv/gerrit/git, so a single full-site tarball would be huge.
For this upgrade, I split the backup into two tarballs:
- One for the Gerrit site without any Git repos
- One for the meta projects (
All-ProjectsandAll-Users)
This assumes you already have a normal backup or snapshot strategy for your actual project repos.
Tarball 1 – Site backup without any Git repositories
This captures config, db, plugins, caches, logs, etc., but excludes the whole git directory:
sudo tar czf /root/gerrit-3.12.2-site-nogit-$(date +%F).tar.gz \
-C /srv/gerrit \
--exclude=./git \
.
No project repos are included in this tarball.
Tarball 2 – Meta projects only (All-Projects, All-Users)
Gerrit stores important metadata in two special repos under /srv/gerrit/git:
All-Projects.git– global configuration, access rules, project defaultsAll-Users.git– per-user settings, preferences, and some account data
Back them up separately:
sudo tar czf /root/gerrit-3.12.2-meta-projects-$(date +%F).tar.gz \
-C /srv/gerrit/git All-Projects.git All-Users.git
These two tarballs together give you:
- Complete site state (configs, db, plugins, caches, etc.)
- All NoteDb metadata (
All-ProjectsandAll-Users) - While leaving large project repos (like AOSP) to your existing backup/snapshot mechanism.
- Download Gerrit 3.13.1 and Replace
gerrit.war
Switch to the gerrit user:
sudo su - gerrit
cd /srv/gerrit/bin
Rename the existing WAR so you can easily roll back:
mv gerrit.war gerrit-3.12.2.war
Download 3.13.1:
wget https://gerrit-releases.storage.googleapis.com/gerrit-3.13.1.war
Point gerrit.war to the new file:
ln -sf gerrit-3.13.1.war gerrit.war
Your /srv/gerrit/bin should now look like:
gerrit-3.12.2.war
gerrit-3.13.1.war
gerrit.war -> gerrit-3.13.1.war
gerrit.sh
(If you keep extra helper files here, they’ll also show up.)
Exit back to your normal user:
exit
- Update Only Existing Core Plugins from the New WAR
For 3.12 → 3.13, schema and index don’t change, but you should update the core plugins you’re already using so they match the Gerrit version.
Switch to gerrit again:
sudo su - gerrit
cd /srv/gerrit
Create a temporary directory and unpack the new WAR:
mkdir -p /srv/gerrit/tmp-war
cd /srv/gerrit/tmp-war
jar xf /srv/gerrit/bin/gerrit-3.13.1.war
Core plugins live under WEB-INF/plugins/.
To overwrite only the core plugins you already use
for p in codemirror-editor delete-project download-commands \
gitiles plugin-manager replication; do
if [ -f "/srv/gerrit/plugins/$p.jar" ]; then
echo "Updating $p.jar"
cp "WEB-INF/plugins/$p.jar" "/srv/gerrit/plugins/$p.jar"
else
echo "Skipping $p.jar (not installed)"
fi
done
External plugins (e.g. Keycloak OAuth)
If you use external plugins, make sure you have versions built against Gerrit 3.13. Replace those JARs in /srv/gerrit/plugins/ if needed.
Clean up:
cd /srv/gerrit
rm -rf tmp-war
exit
- Start Gerrit and Verify the Upgrade
Start Gerrit again:
sudo systemctl start gerrit
sudo systemctl status gerrit
Watch logs to confirm a clean startup:
sudo journalctl -u gerrit -f
Quick HTTP check from the server:
curl -I http://127.0.0.1:8080
Then verify the version:
sudo -u gerrit java -jar /srv/gerrit/bin/gerrit.war version
You should now see:
gerrit version 3.13.1
At this point, the offline upgrade is complete.
Did this guide save you time?
Support this site