1What is SonarQube?
SonarQube is a tool that analyzes your source code to find bugs, vulnerabilities, and quality issues. Think of it as a spell checker, but for programming — it scans every line of code and tells you what needs fixing.
Find bugs early
Detect problems before they reach production, when they're cheaper to fix.
Security by default
Identifies known vulnerabilities in your code following OWASP and CWE standards.
Measure quality
Tracks code coverage, duplication, complexity, and technical debt over time.
100% private
All analysis stays in your server. Nothing is sent to external services.
If your code is a building, SonarQube is the inspector that checks every brick, wire, and pipe before it collapses.
2How to access the dashboard
You only need a web browser and the address of your server. Your administrator will provide it.
Open your browser
Any modern browser works: Chrome, Safari, Edge, or Firefox. No installation needed.
Type the URL
In the address bar, type the server address ending in port 9000:
http://your-server-address:9000
Sign in
Use the credentials provided by your administrator. The default ones are shown in the next section.
Ask your administrator to verify that port 9000 is open in the AWS security group for your IP address. This is a technical step they must handle.
3Sign in for the first time
Each instance gets a unique admin password derived from its cloud identifier. Use the credentials provided by your administrator.
| Field | Default value |
|---|---|
| Username | admin |
| Password | I-<instance-id>B! |
How to find your password
The password always starts with the letter I, followed by your server identifier, and ends with B!. Example: if your server ID is i-0d267b6251f053ad8, the password is I-0d267b6251f053ad8B!.
Go to My Account → Security → Change password. Use a strong password with at least 12 characters. This is critical if your server is exposed to the internet.
4The dashboard at a glance
Once logged in, you will see a clean dashboard with metrics, charts, and a list of recent activity. Everything is designed to be read at a glance.
Main sections
- Projects: list of all code repositories under analysis.
- Issues: detailed list of every bug, vulnerability, or code smell.
- Measures: aggregated metrics like coverage, duplication, and complexity.
- Quality Gates: rules that determine whether a project passes or fails.
5Reading analysis results
An analysis is a scan of your code that produces a report with everything SonarQube found. Here is how to read it.
What each result means
- Bug: a piece of code that is likely to break in production.
- Vulnerability: a security weakness that could be exploited.
- Code Smell: code that works but is hard to maintain.
- Security Hotspot: code that needs manual review for security.
- Coverage: the percentage of your code covered by tests.
- Duplication: how much of your code is repeated.
Start by fixing bugs and vulnerabilities — they affect production. Code smells can wait.
6Managing projects
Each code repository you want to analyze needs to be registered as a project. Your team's developer will handle the technical setup.
What you can do
- View all projects: see the quality status of every repository at once.
- Compare projects: see which ones have more issues.
- Track progress: watch issues go down over time.
- Export reports: download PDF summaries for management.
A "quality gate" is a rule that says whether a project is healthy. A green gate means the code is ready for release.
7Common issues
| Issue | Solution |
|---|---|
| The dashboard is empty | No projects have been analyzed yet. Ask your developer to run the first scan. |
| I cannot log in | Verify the URL is correct (port 9000). If the password does not work, ask your administrator to reset it. |
| The page is very slow | Ask your administrator to check the server load. With many projects, the database may need optimization. |
| Numbers look wrong | Make sure you are viewing the latest analysis. Old analyses are historical and do not reflect current code. |
| I see an error message | Take a screenshot and send it to your administrator with the timestamp. It will help them find the cause. |
8Best practices
For day-to-day use
- Check the dashboard weekly: ten minutes a week keeps quality visible.
- Focus on new issues: fix what was just introduced, not what was there for years.
- Share reports: send screenshots to your team during sprint reviews.
- Do not change settings: leave configuration to your administrator.
What to avoid
- Do not share your password with anyone.
- Do not ignore security vulnerabilities, even if they look minor.
- Do not use SonarQube results as the only quality signal — combine with tests and code reviews.
You are ready!
Open the dashboard and start exploring your code quality data. The best way to learn is by using it.
1Full stack architecture
Complete SonarQube hardened stack deployed on a single EC2 t3.large instance (8 GB RAM) with all security tools preinstalled.
| Layer | Technology | Port |
|---|---|---|
| Operating System | Ubuntu 26.04 LTS (resolute) - kernel 7.0 AWS | - |
| Java Runtime | OpenJDK 21 (required by SonarQube 26.x) | - |
| SonarQube Application | SonarQube 26.9.0.129388 (native, no Docker) | 9000 |
| Relational Database | PostgreSQL 16 (local socket) | 5432 |
| Security Tooling | Lynis, ClamAV, OpenSCAP, auditd, fail2ban | - |
| Firewall | UFW (deny incoming, allow 22 + 9000) | - |
Important system paths
# SonarQube application
/opt/sonarqube/
conf/sonar.properties # Database and JVM config
bin/linux-x86-64/sonar.sh
logs/
# Data directories
/var/sonarqube/
data/ # Elasticsearch indices
temp/ # Scratch space
logs/ # Application logs
# systemd units
/etc/systemd/system/sonarqube.service
/etc/systemd/system/set-sonar-password.service
# Password rotation scripts
/usr/local/bin/set-sonar-password.sh
/usr/local/bin/ver-password.sh
# Credentials (only readable by root)
/root/sonarqube-admin-password.txt
/root/README-AMI.txt
systemd services
sonarqube.service -> main application (forking)
set-sonar-password.service -> rotates admin password on boot (oneshot)
postgresql.service -> database
clamav-freshclam.service -> antivirus signature updates
fail2ban.service -> SSH brute-force protection
auditd.service -> kernel-level audit logging
ufw.service -> host firewall (oneshot)
2Endpoints
SonarQube exposes a web UI, a REST API, and a database connection for direct queries.
| Service | Endpoint | Purpose |
|---|---|---|
| SonarQube UI | http://<host>:9000 | Web dashboard |
| SonarQube API | http://<host>:9000/api | REST API for automation |
| System status | http://<host>:9000/api/system/status | Health check |
| PostgreSQL | localhost:5432 | Direct database access |
Example API calls
# Check SonarQube is up
curl -s http://localhost:9000/api/system/status | jq .
# Verify admin credentials
curl -u admin:AdminDefault1! http://localhost:9000/api/users/current
# List all projects
curl -u admin:PASSWORD http://localhost:9000/api/projects/search
3Password rotation
On every boot, set-sonar-password.service reads the EC2 Instance ID via IMDSv2 and rotates the SonarQube admin password to a deterministic value derived from it.
Password rule
Password = "I-" + + "B!"
Example:
Instance ID: i-0d267b6251f053ad8
Password: I-0d267b6251f053ad8B!
Rotation flow
1. Read Instance ID from IMDSv2:
TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" \
-H "X-aws-ec2-metadata-token-ttl-seconds: 300")
INSTANCE_ID=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \
http://169.254.169.254/latest/meta-data/instance-id)
2. Build PASSWORD = "I-${INSTANCE_ID#i-}B!"
3. Wait for SonarQube to respond on /api/system/status
4. Check if admin/AdminDefault1! still works:
curl -u admin:AdminDefault1! /api/users/current -> 200
5. If yes, POST /api/users/change_password with:
login=admin
previousPassword=AdminDefault1!
password=I-B!
6. Save credentials to /root/sonarqube-admin-password.txt (0600)
Manual rotation
# Force rotation at any time
sudo /usr/local/bin/set-sonar-password.sh
# View current credentials
sudo /usr/local/bin/ver-password.sh
sudo cat /root/sonarqube-admin-password.txt
The build resets the admin hash to AdminDefault1! before creating the AMI so the rotation script has a known starting point. On the first boot of each new instance, the password is rotated to the Instance-ID-derived value.
4systemd services
Basic commands
# Status
sudo systemctl status sonarqube postgresql clamav-freshclam fail2ban auditd
# Restart SonarQube
sudo systemctl restart sonarqube
# Enable/disable at boot
sudo systemctl enable sonarqube
sudo systemctl disable sonarqube
# Check all our services are enabled
sudo systemctl is-enabled sonarqube set-sonar-password postgresql clamav-freshclam fail2ban auditd ufw
sonarqube.service structure
# /etc/systemd/system/sonarqube.service
[Unit]
Description=SonarQube service
After=syslog.target network.target postgresql.service
[Service]
Type=forking
ExecStart=/opt/sonarqube/bin/linux-x86-64/sonar.sh start
ExecStop=/opt/sonarqube/bin/linux-x86-64/sonar.sh stop
User=sonarqube
Group=sonarqube
Restart=on-failure
RestartSec=10
LimitNOFILE=131072
LimitNPROC=8192
LimitCORE=infinity
LimitMEMLOCK=infinity
TasksMax=infinity
Environment="JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64"
Environment="SONAR_JAVA_PATH=/usr/lib/jvm/java-21-openjdk-amd64/bin/java"
[Install]
WantedBy=multi-user.target
Adjust JVM memory
sudo vim /opt/sonarqube/conf/sonar.properties
# Default (t3.large / 8 GB):
sonar.web.javaOpts=-Xmx1536m -Xms512m -XX:+HeapDumpOnOutOfMemoryError
sonar.ce.javaOpts=-Xmx1536m -Xms512m -XX:+HeapDumpOnOutOfMemoryError
sonar.search.javaOpts=-Xmx1024m -Xms1024m -XX:+HeapDumpOnOutOfMemoryError
# Restart after changes
sudo systemctl restart sonarqube
5PostgreSQL
SonarQube uses PostgreSQL for its relational data. Default database and user are both called sonarqube.
Connect
# As the postgres user
sudo -u postgres psql
# Directly into the SonarQube DB
sudo -u postgres psql -d sonarqube
Useful queries
-- List tables
\dt
-- Count users
SELECT count(*) FROM users;
-- Show admin row
SELECT login, hash_method, reset_password
FROM users WHERE login='admin';
-- Recent analysis jobs
SELECT uuid, status, submitted_at
FROM ce_queue
ORDER BY submitted_at DESC LIMIT 10;
Reset admin hash (recovery)
If both AdminDefault1! and the Instance-ID password fail, inject a known hash to recover access:
sudo systemctl stop sonarqube
sudo -u postgres psql -d sonarqube <<'SQL'
UPDATE users
SET crypted_password='100000$t2h8AtNs1AlCHuLobDjHQTn9XppwTIx88UjqUm4s8RsfTuXQHSd/fpFexAnewPsO6jGFQUv/24DnO55hY6Xew==',
salt='k9x9eN127/3e/hf38iNiKwVfaVk=',
hash_method='PBKDF2',
reset_password='false',
user_local='true'
WHERE login='admin';
SQL
sudo systemctl start sonarqube
sleep 120
# admin/admin now works -> change it to AdminDefault1!
curl -u admin:admin -X POST \
"http://localhost:9000/api/users/change_password" \
--data-urlencode "login=admin" \
--data-urlencode "previousPassword=admin" \
--data-urlencode "password=AdminDefault1!"
# Then re-run rotation
sudo /usr/local/bin/set-sonar-password.sh
6Security tools
This AMI ships with a full set of hardened security tools, all installed and enabled at boot.
Installed tools
| Tool | Version | Purpose |
|---|---|---|
| Lynis | 3.1.6 | System hardening audit and score |
| ClamAV | 1.5.4 | Antivirus signature-based scanning |
| OpenSCAP | 1.4.3 | CIS benchmark compliance |
| auditd | latest | Kernel-level audit logging |
| fail2ban | latest | SSH brute-force protection |
| UFW | latest | Host firewall (deny incoming) |
| unattended-upgrades | latest | Automatic security patches |
How to run them
# Lynis full audit
sudo lynis audit system
sudo grep -E "^\s*(warning|suggestion)" /var/log/lynis-report.dat | head -40
# ClamAV scan
sudo clamscan -r /opt
sudo systemctl status clamav-freshclam
# OpenSCAP CIS Level 1
sudo oscap xccdf eval \
--profile xccdf_org.ssgproject.content_profile_cis_level1_server \
--results /root/openscap-results.xml \
--report /root/openscap-report.html \
/usr/share/xml/scap/ssg/content/ssg-ubuntu2404-ds.xml
# auditd
sudo systemctl status auditd
sudo ausearch -ts today | head -20
# fail2ban
sudo fail2ban-client status sshd
# UFW
sudo ufw status verbose
Hardening applied at build
- Kernel sysctl:
vm.max_map_count=524288,fs.file-max=131072,kernel.dmesg_restrict=1,kernel.kptr_restrict=2 - User limits:
nofile=131072,nproc=8192for thesonarqubeuser - Firewall: default deny incoming, ports 22 + 9000 open
- Audit rules: Neo23x0 baseline loaded into
/etc/audit/rules.d/audit.rules - Automatic security updates enabled
On this image, Lynis produces a hardening index between 75 and 85 out of 100. Remaining suggestions are usually about SSH configuration (which is intentionally left untouched) and optional PAM tweaks.
7Logs and monitoring
Service logs
sudo journalctl -u sonarqube -f
sudo journalctl -u sonarqube -n 200 --no-pager
sudo journalctl -u set-sonar-password --no-pager | tail -30
Application logs
sudo tail -f /var/sonarqube/logs/sonar.log
sudo tail -f /var/sonarqube/logs/web.log
sudo tail -f /var/sonarqube/logs/es.log # Elasticsearch
sudo tail -f /var/sonarqube/logs/ce.log # Compute Engine
System monitoring
free -h
df -h /
top -b -n 1 | head -20
sudo ss -tulpn | grep -E ':(5432|9000)'
Ports
sudo ss -tulpn | grep -E ':(22|5432|9000)'
8Troubleshooting
| Symptom | Cause | Solution |
|---|---|---|
SonarQube stuck on STARTING |
Elasticsearch still booting (cold start) | Wait 5 min, then check /var/sonarqube/logs/es.log |
| Service failed with OOM | Instance RAM too small | Resize to t3.large (8 GB) |
| Password rotation never runs | IMDSv2 blocked or service disabled | sudo systemctl enable --now set-sonar-password.service |
| Both passwords return 401 | Unknown password state | Reset hash via PostgreSQL (see PostgreSQL section) |
| Port 9000 unreachable | Security Group missing rule | Add inbound TCP 9000 |
!BA: event not found in bash |
History expansion in interactive shell | Run set +H or use single quotes |
Quick diagnostic
# Services
systemctl is-active sonarqube postgresql clamav-freshclam fail2ban auditd
systemctl is-enabled sonarqube set-sonar-password postgresql clamav-freshclam fail2ban auditd ufw
# Ports
sudo ss -tulpn | grep -E ':(22|5432|9000)'
# SonarQube API
curl -s http://localhost:9000/api/system/status | jq .
# Default password check
set +H
curl -u 'admin:AdminDefault1!' -s -o /dev/null -w "%{http_code}\n" \
http://localhost:9000/api/users/current
# Rotation log
sudo journalctl -u set-sonar-password.service --no-pager | tail -20
# Resources
free -h
df -h /
9AMI notes
This AMI starts SonarQube, PostgreSQL, ClamAV, fail2ban, auditd, and UFW automatically via systemd on every boot. No manual intervention is required.
Startup timeline
| Time | Event |
|---|---|
| T+0s | Instance starts |
| T+10s | PostgreSQL starts |
| T+15s | SonarQube service begins startup |
| T+90s | Elasticsearch ready, web server starting |
| T+180s | SonarQube reports UP |
| T+185s | Password rotation runs and completes |
| T+190s | UI available at http://<ip>:9000 |
Launching multiple instances
To launch several instances from this AMI, ensure your security group allows inbound traffic to port 9000 from your management CIDR:
aws ec2 authorize-security-group-ingress \
--group-id sg-xxxxxxxx \
--protocol tcp \
--port 9000 \
--cidr <your-ip>/32
Instance recommendations
| Instance Type | RAM | Verdict |
|---|---|---|
| t3.small / t3.micro | 2 GB | Will OOM |
| t3.medium | 4 GB | Minimum |
| t3.large | 8 GB | Recommended |
| t3.xlarge | 16 GB | Comfortable |
Username: admin — Default password before rotation: AdminDefault1!. After the first boot, the password is I-<instance-id>B!. Change it after first login in production.
Files to know about
| Path | Purpose |
|---|---|
/root/README-AMI.txt | Full usage guide |
/root/sonarqube-admin-password.txt | Auto-generated credentials file |
/root/openscap-report.html | CIS benchmark report |
/usr/local/bin/ver-password.sh | Show credentials |
/usr/local/bin/set-sonar-password.sh | Force password rotation |
/opt/sonarqube/conf/sonar.properties | Application config |