This guide walks through installing Gerrit Code Review, securing it with NGINX as a reverse proxy, and configuring HTTPS using SSL certificates.
Tested with Ubuntu 22.04/24.04 and Gerrit 3.9.x.
1. Install Required Packages
Run the following on the VM that will host Gerrit:
apt install -y openjdk-17-jdk git apache2-utils nginx
2. Create User Accounts with htpasswd
NGINX uses an .htpasswd file to store usernames and hashed passwords.
Create the first user (admin):
sudo htpasswd -c /etc/nginx/.htpasswd admin
Add additional users (without -c):
sudo htpasswd /etc/nginx/.htpasswd sandeep
Repeat for as many users as needed.
3. Install SSL Certificates
Place your certificate files in:
/etc/ssl/certs/yourdomain.crt
/etc/ssl/private/yourdomain.key
/etc/ssl/certs/ca_bundle.crt
3.1 Set Secure Permissions
chmod 640 /etc/ssl/private/yourdomain.key
chown root:www-data /etc/ssl/private/yourdomain.key
chmod 644 /etc/ssl/certs/yourdomain.crt
chown root:root /etc/ssl/certs/yourdomain.crt
chmod 644 /etc/ssl/certs/ca_bundle.crt
chown root:root /etc/ssl/certs/ca_bundle.crt
4. Configure NGINX Reverse Proxy for Gerrit
Create the file:
/etc/nginx/sites-available/gerrit.conf
NGINX Configuration
server {
listen 443 ssl http2;
server_name gerrit.yourdomain.com git.yourdomain.com;
# SSL certificates
ssl_certificate /etc/ssl/certs/yourdomain.crt;
ssl_certificate_key /etc/ssl/private/yourdomain.key;
ssl_trusted_certificate /etc/ssl/certs/ca_bundle.crt;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# Security headers
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
location / {
auth_basic "Gerrit Login";
auth_basic_user_file /etc/nginx/.htpasswd;
proxy_set_header SM_USER $remote_user;
proxy_http_version 1.1;
proxy_read_timeout 600s;
proxy_connect_timeout 600s;
proxy_send_timeout 600s;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto https;
# Gerrit listens on 127.0.0.1 by default
proxy_pass http://127.0.0.1:8080;
proxy_request_buffering off;
proxy_buffering off;
chunked_transfer_encoding off;
}
}
server {
listen 80;
server_name gerrit.yourdomain.com git.yourdomain.com;
return 301 https://$host$request_uri;
}
4.1 Enable the NGINX Site
ln -s /etc/nginx/sites-available/gerrit.conf /etc/nginx/sites-enabled/gerrit.conf
unlink /etc/nginx/sites-enabled/default
nginx -t
systemctl reload nginx
5. Create Gerrit User and Download Gerrit
adduser --disabled-password --gecos "" gerrit
sudo su - gerrit
5.1 Download the Gerrit WAR
wget https://gerrit-releases.storage.googleapis.com/gerrit-3.9.1.war -O gerrit.war
5.2 Pre-Populate gerrit.config
mkdir ~/etc
cat <<EOF > ~/etc/gerrit.config
[gerrit]
basePath = git
# Ensure this matches your DNS
canonicalWebUrl = https://gerrit.datachronicles.net
serverId = datachronicles-gerrit
[database]
type = h2
database = db/ReviewDB
[index]
type = lucene
[auth]
type = HTTP
logoutUrl = https://gerrit.datachronicles.net
httpHeader = SM_USER
[receive]
enableSignedPush = false
[sendemail]
smtpServer = localhost
[sshd]
listenAddress = *:29418
[httpd]
listenUrl = proxy-https://127.0.0.1:8080/
[cache]
directory = cache
[plugins]
allowRemoteAdmin = true
[container]
javaOptions = "-Dflogger.backend_factory=com.google.common.flogger.backend.log4j.Log4jBackendFactory#getInstance"
javaOptions = "-Dflogger.logging_context=com.google.gerrit.server.logging.LoggingContext#getInstance"
user = gerrit
javaHome = /usr/lib/jvm/java-17-openjdk-amd64
EOF
5.3 Initialize Gerrit
java -jar gerrit.war init -d ~/ --install-all-plugins
Location of Git repositories [git]:
Type [lucene]:
Authentication method [http/?]:
Get username from custom HTTP header [Y/n]?
Username HTTP header [SM_USER]:
SSO logout URL [https://gerrit.datachronicles.net]:
Enable signed push support [y/N]?
Install Verified label [y/N]? Y
Run as [gerrit]:
Java runtime [/usr/lib/jvm/java-17-openjdk-amd64]:
Copy gerrit.war to /home/gerrit/bin/gerrit.war [Y/n]?
Listen on address [*]:
Listen on port [29418]:
Behind reverse proxy [Y/n]?
Proxy uses SSL (https://) [Y/n]?
Subdirectory on proxy server [/]:
Listen on address [127.0.0.1]:
Listen on port [8080]:
Canonical URL [https://gerrit.datachronicles.net]:
exit
5.4 Create a Systemd Service
tee /etc/systemd/system/gerrit.service <<EOF
[Unit]
Description=Gerrit Code Review
After=network.target
[Service]
Type=forking
User=gerrit
Group=gerrit
Environment="GERRIT_SITE=/home/gerrit"
ExecStart=/home/gerrit/bin/gerrit.sh start
ExecStop=/home/gerrit/bin/gerrit.sh stop
TimeoutSec=300
Restart=on-failure
PIDFile=/home/gerrit/logs/gerrit.pid
[Install]
WantedBy=multi-user.target
EOF
Reload and Start Gerrit
systemctl daemon-reload
systemctl enable --now gerrit
systemctl status gerrit
5.6 Access Gerrit & Configure “Verified” Label
Go to:
https://gerrit.yourdomain.com
Login using the credentials created with htpasswd.
Add the Verified label:
Browse → Repositories → All Projects → Edit- Scroll to Reference: refs/heads/*
- Click Add under Label Verified
- Assign groups (e.g., Administrators, Registered Users)
- Click Save
Authentication Notes
When Gerrit is deployed behind NGINX using auth.type = HTTP, password verification is performed entirely by the reverse proxy (NGINX) and not by Gerrit itself. In this mode, users authenticate against NGINX (typically via an .htpasswd file), and NGINX forwards the authenticated username to Gerrit through a header such as SM_USER. Gerrit simply trusts this header and does not check passwords internally. While this mechanism works perfectly for web access, Git clients do not participate in the same authentication flow. Git over HTTPS requires Gerrit’s own internal HTTP password (generated under Settings → HTTP Credentials), which often causes confusion. For this reason, when using Gerrit + Git repositories, SSH-based Git access (port 29418) is strongly recommended—it is simpler, avoids HTTP credential mismatches, integrates cleanly with Gerrit’s SSH key system, and eliminates issues related to proxy authentication and Git Credential Manager on Windows.
Cleaning Git Credential Manager (GCM) on Windows
When using Git for Windows, the Git Credential Manager (GCM Core) can silently interfere with Gerrit authentication by injecting cached or invalid credentials—even when no credential.helper is configured in Git. This causes Git HTTPS operations to fail with “Unauthorized” despite valid server-side authentication. To fully disable GCM, remove all helper entries from Git and clear stored credentials. Run:
git config --global --unset-all credential.helper
git config --system --unset-all credential.helper
git config --global credential.helper " "
Then delete Windows-stored Git credentials:
cmdkey /list
cmdkey /delete:git:https://<your-domain>
cmdkey /delete:git:http://<your-domain>
Optionally, disable GCM for the session:
export GCM_CREDENTIAL_STORE=none
After cleaning GCM, Git will prompt for credentials normally, or (preferably) you can switch entirely to SSH keys, which bypasses GCM and avoids these issues permanently.