CodeChecker 6 on Ubuntu 24.04 on Azure User Guide
Overview
CodeChecker is an open source static analysis platform. It drives established analysers over your C and C++ source, collects everything they report into a single database, and gives your team a web interface for triaging the results: marking a finding as a real bug or a false positive, leaving a comment, and tracking whether a defect is new, still outstanding, or fixed compared with a previous run.
The value is in the workflow rather than the analysis alone. Running clang-tidy by hand produces a wall of text that is thrown away when the terminal closes. CodeChecker stores each analysis as a named run, so you can diff today's results against last week's, suppress a false positive once and never see it again, and give reviewers a link to a specific defect with its full execution path highlighted in the source.
The cloudimg image serves CodeChecker 6.28.2 on a hardened, fully patched Ubuntu 24.04 LTS base. The analysers ship with it — Clang Static Analyzer, Clang-Tidy and Cppcheck are installed and pinned, so you can analyse a project the moment the VM boots instead of installing a compiler first. The server runs in its own Python virtualenv as a dedicated service account, listens only on the loopback interface, and is published by nginx on port 80. Backed by 24/7 cloudimg support.
Two things about this image are worth stating plainly.
Authentication is switched on. Upstream CodeChecker ships with authentication disabled, which means anyone who can reach the port can read every stored finding — file paths, source snippets and defect locations from your own code. This image does not ship that posture. A unique administrator credential is generated on the first boot of every VM, only a salted SHA-512 hash of it is ever written to disk, and the server refuses to start at all if no credential is configured.
The image proves itself. A small C project with four deliberate defects ships with the image and is analysed at build time. First boot stores that analysis as a run called cloudimg-sample-c, so the first time you sign in you see real findings with real bug paths rather than an empty database. You can re-run the whole cycle at any time with a single command, and you can delete the run once your own code is in there.
Trademark notice. CodeChecker is an open source project maintained by Ericsson AB and released under Apache-2.0 WITH LLVM-exception. "Ericsson" is a trademark of Telefonaktiebolaget LM Ericsson; "LLVM" and "Clang" are trademarks of the LLVM Foundation. They are used in this guide only to describe the software's provenance and the analysers it invokes. cloudimg is not affiliated with, endorsed by, or sponsored by any of them.
What is included:
- CodeChecker 6.28.2 in a dedicated Python 3.12 virtualenv, managed by systemd
- The analyser toolchain: Clang Static Analyzer and Clang-Tidy 18.1.3, Cppcheck 2.13.0, GCC 13.3.0
- The web interface and the full API on
:80, behind CodeChecker's own authentication from the first request - A per VM administrator credential generated on first boot, holding the
SUPERUSERpermission - Only a salted SHA-512 hash of that credential stored on disk, never the password itself
- The server bound to
127.0.0.1:8001only, never exposed directly to the network - A bundled SQLite database — no external database service to run or pay for
- A sample analysis stored on first boot so the product is provably working on day one
- An open
/liveendpoint for Azure Load Balancer health probes - 24/7 cloudimg support
Prerequisites
- An Azure subscription
- A VM size with at least 2 vCPUs and 4 GiB of memory.
Standard_B2sis the recommended size and is what this guide uses. - Inbound TCP 80 open to the networks you want to serve, and TCP 22 if you want SSH access
Step 1 - Deploy from the Azure Marketplace
Search the Azure Marketplace for CodeChecker 6 on Ubuntu 24.04 by cloudimg, select Create, choose Standard_B2s, and allow inbound TCP 80 and TCP 22. Complete the wizard and wait for the deployment to finish.
Step 2 - Deploy from the Azure CLI
az group create --name codechecker-rg --location eastus
az vm create \
--resource-group codechecker-rg \
--name codechecker-vm \
--image cloudimg:codechecker-ubuntu-24-04:codechecker-ubuntu-24-04:latest \
--size Standard_B2s \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku Standard
az vm open-port --resource-group codechecker-rg --name codechecker-vm --port 80
First boot generates the administrator credential, starts the server and stores the sample analysis. This takes about a minute; the steps below wait for it where it matters.
Step 3 - Confirm the services are running
SSH to the VM and check the two units. codechecker.service is the analysis server, nginx.service is the only routable listener.
systemctl is-active codechecker nginx
active
active
Confirm the server is bound to loopback and only nginx is exposed:
ss -ltn | grep -E ':80 |:8001 '
LISTEN 0 511 0.0.0.0:80 0.0.0.0:*
LISTEN 0 511 127.0.0.1:8001 0.0.0.0:*
LISTEN 0 511 [::]:80 [::]:*
8001 is bound to 127.0.0.1 only. The server is never reachable directly from the network — every request arrives through nginx on port 80.
The /live endpoint is the one unauthenticated path. It exists so an Azure Load Balancer health probe can confirm the VM is up without being given a credential, and it returns a fixed string rather than any product data:
curl -s http://127.0.0.1/live
ok

Step 4 - Confirm the analysers shipped with the image
CodeChecker is a driver: it orchestrates other analysers. This image installs them so you do not have to. Ask CodeChecker what it can see:
/opt/codechecker/venv/bin/CodeChecker analyzers --detail
clangsa /usr/lib/llvm-18/bin/clang 18.1.3
clang-tidy /usr/lib/llvm-18/bin/clang-tidy 18.1.3
cppcheck /usr/bin/cppcheck 2.13.0
gcc /usr/bin/x86_64-linux-gnu-g++-13 13.3.0
infer NOT FOUND
Four analysers are available. infer (Facebook Infer) is not shipped — it is a large JVM-based toolchain with its own licensing and is better installed deliberately if you need it.
The exact versions are also recorded in a file at build time:
cat /etc/codechecker/analyzer-versions.txt
# Analyser toolchain shipped in this cloudimg CodeChecker image.
# Recorded at build time from the Ubuntu 24.04 archive packages.
clang=Ubuntu clang version 18.1.3 (1ubuntu1)
clang-tidy=Ubuntu LLVM version 18.1.3
cppcheck=Cppcheck 2.13.0
gcc=gcc (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0
gpp=g++ (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0
python3=Python 3.12.3

All of these come from the Ubuntu 24.04 archive, so they keep receiving security updates through the VM's normal unattended-upgrades configuration.
Step 5 - Retrieve the per VM administrator credential
The credential is generated on first boot and written to a root-only file:
sudo cat /root/codechecker-credentials.txt
The interesting lines are:
CODECHECKER_URL=http://<vm-public-ip>/
codechecker.admin.user=<CC_ADMIN_USER>
codechecker.admin.pass=<CC_ADMIN_PASSWORD>
This account holds the SUPERUSER permission, so it can administer products and grant access to other users from the web interface.
The password is unique to this VM, generated from the kernel CSPRNG on first boot. It is not known to cloudimg and is not derived from anything predictable. Note that only a salted SHA-512 hash of it is stored in the server configuration:
sudo python3 -c "import json; e=json.load(open('/etc/codechecker/server_config.json'))['authentication']['method_dictionary']['auths'][0]; f=e.split(':'); print('user :', f[0]); print('algorithm :', f[2]); print('hash :', f[1][:32] + '...'); print('salt :', f[3])"
user : ccadmin
algorithm : sha512
hash : 4d0afceddc54962cf5b4054091c094cf...
salt : 1f3c9ab27d4e5068bb1cf0a4e7d29c31
The plaintext password appears nowhere except the root-only credentials file above.
Step 6 - Confirm there is no default login
Two things must be true for this appliance to be safe to expose: authentication must be enabled, and no guessable credential may work. Confirm the first:
sudo grep -A2 '"authentication"' /etc/codechecker/server_config.json | head -4
"authentication": {
"enabled": true,
"super_user": "ccadmin",
Now confirm a well-known guess is refused:
export HOME=/root
sudo rm -f /root/.codechecker.session.json
sudo CC_PASSWORD=admin /opt/codechecker/venv/bin/CodeChecker cmd login ccadmin --url http://127.0.0.1 2>&1 | tail -3 || true
A refused login also exits non-zero, which is why the command ends with || true — that keeps the shell happy while still showing you the refusal.
[ERROR 2026-08-07 16:41:08] - Authentication denied
Invalid credentials supplied for user 'ccadmin'. Refusing authentication!
Note: Invalid credentials.
And that an unauthenticated client cannot read stored results:
sudo CC_PASSWORD=wrong /opt/codechecker/venv/bin/CodeChecker cmd runs --url http://127.0.0.1/Default 2>&1 | tail -2 || true
[ERROR 2026-08-07 16:41:08] - Invalid pre-configured credentials.
[ERROR 2026-08-07 16:41:08] - Your password has been changed or personal access token has been removed which is used by your "/root/.codechecker.passwords.json"

Step 7 - Sign in to the web interface
Browse to http://<vm-public-ip>/. Because authentication is enabled, an anonymous visitor is redirected to the login form rather than shown any data:

Sign in with the username and password from Step 5. You land on the product list. A single product, Default, is created on first boot and is backed by the bundled SQLite database:

Select Default to see its runs. The cloudimg-sample-c run was stored on first boot:

Step 8 - Read the findings that are already there
Open the REPORTS tab. The sample run contains seven findings across four source files, each with its checker name, severity, message and bug path length:

The same list is available from the command line:
export HOME=/root
sudo rm -f /root/.codechecker.session.json
sudo CC_PASSWORD='<CC_ADMIN_PASSWORD>' /opt/codechecker/venv/bin/CodeChecker cmd login '<CC_ADMIN_USER>' --url http://127.0.0.1 >/dev/null
sudo /opt/codechecker/venv/bin/CodeChecker cmd results cloudimg-sample-c --url http://127.0.0.1/Default | head -12
File | Checker | Severity | Message | Bug path length | Analyzer name | Review status | Detection status
/opt/codechecker/sample-project/src/null_deref.c @ 24 | core.NullDereference | HIGH | Access to field 'id' results in a dereference of a... | 2 | clangsa | UNREVIEWED | UNRESOLVED
/opt/codechecker/sample-project/src/div_zero.c @ 16 | core.DivideZero | HIGH | Division by zero | 2 | clangsa | UNREVIEWED | UNRESOLVED
/opt/codechecker/sample-project/src/uninit_value.c @ 8 | core.uninitialized.Assign | HIGH | The left expression of the compound assignment is ... | 4 | clangsa | UNREVIEWED | UNRESOLVED
/opt/codechecker/sample-project/src/uninit_value.c @ 10 | core.uninitialized.UndefReturn | HIGH | Undefined or garbage value returned to caller | 4 | clangsa | UNREVIEWED | UNRESOLVED
/opt/codechecker/sample-project/src/uninit_value.c @ 8 | clang-diagnostic-uninitialized | HIGH | variable 'total' is uninitialized when used here | 2 | clang-tidy | UNREVIEWED | UNRESOLVED
/opt/codechecker/sample-project/src/mem_leak.c @ 22 | unix.Malloc | MEDIUM | Potential leak of memory pointed to by 'label' | 6 | clangsa | UNREVIEWED | UNRESOLVED
/opt/codechecker/sample-project/src/null_deref.c @ 13 | cert-err33-c | MEDIUM | the value returned by this function should not be ... | 2 | clang-tidy | UNREVIEWED | UNRESOLVED

Click any finding in the web interface to open the report detail. This is where CodeChecker earns its place over raw analyser output: the full execution path that leads to the defect is laid over the real source, step by step.

The STATISTICS tab summarises the run by checker and severity:

Step 9 - Analyse your own project
CodeChecker needs a compilation database — a compile_commands.json describing how each file is compiled. There are three ways to get one, and you should pick the first that applies to your project.
If you build with CMake, ask CMake for it directly:
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -S . -B build
If you build with make or a custom script, let CodeChecker observe the build:
CodeChecker log --build "make" --output ./compile_commands.json
Otherwise, write it by hand. The format is a list of objects with directory, command and file. That is the approach the bundled sample uses, and it is perfectly reasonable for a small project.
Here is the whole cycle on a throwaway example, so you can see each command produce real output:
mkdir -p /tmp/demo-project && cd /tmp/demo-project
cat > example.c <<'EOF'
#include <stdlib.h>
int main(void) {
int *p = malloc(sizeof(int));
return *p;
}
EOF
cat > compile_commands.json <<'EOF'
[{"directory":"/tmp/demo-project","command":"/usr/bin/gcc -c /tmp/demo-project/example.c -o /tmp/demo-project/example.o","file":"/tmp/demo-project/example.c"}]
EOF
/opt/codechecker/venv/bin/CodeChecker analyze compile_commands.json -o ./reports --analyzers clangsa 2>&1 | tail -4
[INFO 2026-08-07 16:42:02] - Analysis finished.
[INFO 2026-08-07 16:42:02] - To view results in the terminal use the "CodeChecker parse" command.
[INFO 2026-08-07 16:42:02] - To store results use the "CodeChecker store" command.
[INFO 2026-08-07 16:42:02] - Analysis length: 0.13 sec.
Read the results in the terminal without storing them:
cd /tmp/demo-project && /opt/codechecker/venv/bin/CodeChecker parse ./reports 2>&1 | head -8 || true
[HIGH] /tmp/demo-project/example.c:4:5: Undefined or garbage value returned to caller [core.uninitialized.UndefReturn]
return *p;
^
Found 1 defect(s) in example.c
The analyser correctly reports that malloc may return uninitialised memory which is then returned to the caller.
Exit codes matter if you script this.
CodeChecker parseexits 2 when it finds defects and 0 when it finds none — that is deliberate, so a CI job can fail a build on new findings. It is also why the command above ends with|| true: without it, a shell running underset -ewould stop at the first defect found.
Now store it as a named run so it appears in the web interface alongside the sample:
export HOME=/root
cd /tmp/demo-project
sudo rm -f /root/.codechecker.session.json
sudo CC_PASSWORD='<CC_ADMIN_PASSWORD>' /opt/codechecker/venv/bin/CodeChecker cmd login '<CC_ADMIN_USER>' --url http://127.0.0.1 >/dev/null
sudo /opt/codechecker/venv/bin/CodeChecker store ./reports --name demo-project --url http://127.0.0.1/Default 2>&1 | tail -3
Refresh the RUNS tab and demo-project is there next to cloudimg-sample-c.
To analyse a real project, point the same three commands at it: generate compile_commands.json, run CodeChecker analyze, then CodeChecker store --name <a-name-you-choose>. Storing under the same run name each time is what enables the new/resolved comparison between builds.
Step 10 - Re-run the bundled sample at any time
A helper script runs the full analyse-and-store cycle against the bundled sample project. It reads the per VM credential itself, so it must be run with sudo:
sudo codechecker-analyze-sample
Pass a run name if you want it stored under a different name, for example sudo codechecker-analyze-sample my-baseline. This is a good way to confirm the whole pipeline is healthy after a configuration change.
Step 11 - Add users and products
The account from Step 5 holds SUPERUSER, so it can do both from the web interface.
Users. CodeChecker's dictionary authentication is configured in /etc/codechecker/server_config.json under authentication.method_dictionary.auths. Entries use the format username:hash:algorithm:salt, where the hash is the hex digest of the password with the salt appended. Generate one like this, then add it to the auths list and restart the server:
python3 -c "
import hashlib, secrets, string
pw = ''.join(secrets.choice(string.ascii_letters + string.digits) for _ in range(28))
salt = secrets.token_hex(16)
print('password :', pw)
print('entry : newuser:%s:sha512:%s' % (hashlib.sha512((pw + salt).encode()).hexdigest(), salt))
"
Record the password somewhere safe — it is not recoverable from the hash. Then:
sudo nano /etc/codechecker/server_config.json # add the entry to authentication.method_dictionary.auths
sudo systemctl restart codechecker
CodeChecker also supports PAM, LDAP and OAuth authentication if you would rather delegate to an existing identity provider; see the upstream authentication documentation for the configuration blocks.
Products. A product is a separate results database — most teams use one per codebase. Add one from the PRODUCTS tab, or from the command line, giving it its own SQLite file:
CodeChecker cmd products add myproduct --name "My Product" \
--sqlite /var/lib/codechecker/workspace/myproduct.sqlite \
--url http://127.0.0.1/
Step 12 - Verify the stack
A short set of checks you can re-run at any time:
echo "--- services ---"
systemctl is-active codechecker nginx
echo "--- server is loopback only ---"
ss -ltn | grep ':8001 '
echo "--- authentication is enabled ---"
sudo python3 -c "import json;a=json.load(open('/etc/codechecker/server_config.json'))['authentication'];print('enabled =',a['enabled']);print('dictionary =',a['method_dictionary']['enabled']);print('credentials configured =',len(a['method_dictionary']['auths']))"
echo "--- credential is hashed, not plaintext ---"
sudo grep -c ':sha512:' /etc/codechecker/server_config.json
echo "--- analysers ---"
/opt/codechecker/venv/bin/CodeChecker analyzers 2>/dev/null | head -5
echo "--- open probe ---"
curl -s http://127.0.0.1/live
--- services ---
active
active
--- server is loopback only ---
LISTEN 0 511 127.0.0.1:8001 0.0.0.0:*
--- authentication is enabled ---
enabled = True
dictionary = True
credentials configured = 1
--- credential is hashed, not plaintext ---
1
--- analysers ---
clangsa
clang-tidy
cppcheck
gcc
--- open probe ---
ok
Step 13 - Back up your data
Everything that matters lives in the workspace directory: the configuration database (products, users, sessions) and one SQLite file per product.
sudo systemctl stop codechecker
sudo tar czf /root/codechecker-backup-$(date +%F).tar.gz -C /var/lib/codechecker workspace
sudo systemctl start codechecker
ls -lh /root/codechecker-backup-*.tar.gz
Stopping the server first guarantees a consistent SQLite snapshot. Copy the archive to Azure Blob Storage or another durable location.
Note that this archive deliberately does not include /etc/codechecker/server_config.json or /root/codechecker-credentials.txt. Those hold your credential material and should be handled separately and more carefully.
Security notes
- Authentication is enabled and cannot be silently turned off. The server runs a guard before every start that refuses to launch unless authentication is enabled, the dictionary method is on, and a non-placeholder credential in salted-hash format is present. Editing the configuration to disable authentication will stop the server from starting rather than quietly exposing your findings.
- Only a hash is stored. The per VM password exists in plaintext solely in
/root/codechecker-credentials.txt(mode 0600, owned by root). The server configuration holds a salted SHA-512 hash. - The server is not directly reachable. It binds
127.0.0.1:8001. All external traffic arrives through nginx on port 80. - Restrict port 80. Analysis results describe your source code in detail — file paths, code snippets and defect locations. Limit inbound 80 in your network security group to the networks that need it.
- Terminate TLS in front of the appliance. The image serves plain HTTP so it can sit behind whatever your organisation already uses. Put an Azure Application Gateway, a Load Balancer with TLS termination, or your own reverse proxy in front of it before exposing it beyond a trusted network. Credentials are submitted through a login form, so this matters.
- The sample run is yours to delete. Once your own code is in the database, remove
cloudimg-sample-cfrom the RUNS tab if you would rather not keep it. - Keep the OS patched. Unattended-upgrades is enabled, and every analyser comes from the Ubuntu archive so it is covered. CodeChecker itself is a pinned install inside its virtualenv and is deliberately not auto-upgraded, because its report database schema is version-coupled — upgrade it deliberately, with a backup taken first.
Support
This image is published and supported by cloudimg with 24/7 support. Contact us at www.cloudimg.co.uk with the VM size, the region, and the output of Step 12.
CodeChecker is an open source project maintained by Ericsson AB under the Apache-2.0 WITH LLVM-exception licence. cloudimg is not affiliated with, endorsed by, or sponsored by Ericsson, the LLVM Foundation, or the Cppcheck project.