Developer Tools AWS

CDash 5.5.2 on AWS User Guide

| Product: CDash 5.5.2 on Ubuntu 24.04 on AWS

Overview

This guide covers launching and using the CDash 5.5.2 on Ubuntu 24.04 AMI from cloudimg on Amazon EC2. It is one version of the cloudimg Hardened Apache Subversion (SVN) & CI/CD Tools listing on AWS Marketplace; you pick it as the software version when you subscribe and launch.

CDash is Kitware's open source dashboard server for software testing. CMake's test driver CTest submits each build's configure output, compiler warnings and errors, test results, coverage and memory-checker results to CDash, which shows them per project, build group and machine, with history, test timing, filters, e-mail notifications and an API.

The cloudimg image adds:

  • Nothing shared between instances. The image ships no database, no configuration file and no account. Your instance's first boot creates its own PostgreSQL 16 database cluster, CDash's application key, the administrator's password and the HTTPS certificate. The web server, PHP and CDash's background services do not start until first boot has finished; if it cannot finish, CDash stays offline rather than open.
  • No database password to leak. PostgreSQL has no network listener at all. CDash connects over a local socket as its own operating-system user, and PostgreSQL accepts that user (and only that user) for the cdash database through peer authentication, so there is no database password anywhere.
  • HTTPS from the first boot. nginx serves CDash on port 443 with a certificate generated on your instance. Port 80 redirects to HTTPS, and requests for a host name the instance does not serve are dropped.
  • Token-authenticated CTest submissions. CDash is set to require authenticated submissions: every project a non-administrator creates must use authentication tokens, and the projects you create should have Authenticate submissions ticked (Step 7). A submission without the project's token is refused.
  • No public sign-up, no anonymous password reset. Self-registration is off (you add users). CDash 5.5.2's old password-recovery page sets a new random password for any e-mail address and mails it, which lets anyone lock the administrator out, so it is not served; CDash replaced it after 5.5.2.
  • Cross-site requests refused. CDash 5.5.2 exempts its older .php endpoints from its own form-token check, so nginx refuses every request that changes something unless it comes from your CDash pages themselves. The one exception is CTest's submission endpoint, /submit.php, in its exact form, which is protected by the project tokens instead.
  • A PHP that cannot reach the shell or your network. PHP runs as its own user and cannot change the CDash code. In the web server and in the background services alike it cannot run programs, fork, change its environment, send mail with mail(), load extensions or use FFI; a program saved into a writable folder cannot be executed; and CDash cannot open connections to loopback, link-local, private (RFC 1918), carrier-grade NAT, IPv6 unique-local or metadata addresses, whatever spelling a URL uses. Outbound calls to the internet (GitHub, your SMTP relay) still work.
  • Submitter content sandboxed. Test images and uploaded build files are served with a content security policy that stops any script in them from running on your CDash site.
  • The real host and client address. CDash builds every link from the host name you configure, never from a request header, and records the address of the connection, never a forwarded header.
  • Rate limits. 10 sign-in attempts a minute from one address (on top of CDash's own lockout after 5 failures), 600 submissions a minute, 300 other changes a minute and 1,800 requests a minute.
  • Metadata service blocked for nginx, PHP, PostgreSQL, CDash's queue worker and scheduler and the first boot service; the AMI requires IMDSv2.
  • PHP 8.4 from the ondrej/php PPA. CDash 5.5.2 needs PHP 8.4 and Ubuntu 24.04 ships PHP 8.3, so PHP 8.4 comes from the ondrej/php PPA, trusted only through its pinned signing key and allowed to provide PHP packages only. Unattended upgrades keep it patched along with Ubuntu.
  • Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.

Prerequisites

  • An AWS account subscribed to the listing, an EC2 key pair and a VPC subnet with a route to the internet (or a private route you use for management).
  • A security group that allows TCP 22 (SSH), TCP 443 (CDash) and TCP 80 (redirects to HTTPS) from the networks that should reach them: your team's browsers and every machine that runs CTest. Keep 22 to your own networks.

Step 1: Launch the instance

In the AWS Marketplace listing choose Continue to Subscribe, then Continue to Configuration, pick CDash 5.5.2 on Ubuntu 24.04 as the software version and your Region, then Launch through EC2. Choose m5.large (or larger for many projects or large submissions), your key pair and a security group as above.

With the AWS CLI (replace the values in angle brackets):

aws ec2 run-instances --region <region> --image-id <ami-id-from-the-listing> \
  --instance-type m5.large --key-name <your-key-pair> \
  --security-group-ids <your-security-group> --subnet-id <your-subnet> \
  --metadata-options HttpTokens=required,HttpEndpoint=enabled \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=cdash}]'

Step 2: Connect to your instance

Version SSH user
CDash 5.5.2 on Ubuntu 24.04 ubuntu
ssh -i <your-key.pem> ubuntu@<public-ip>

Step 3: Check the services

First boot takes under a minute. Then nginx, PHP, PostgreSQL, CDash's queue worker and scheduler and the first boot unit are active:

systemctl is-active nginx php8.4-fpm postgresql@16-main cdash-worker cdash-scheduler cdash-firstboot
active
active
active
active
active
active

nginx serves ports 80 and 443; PHP and PostgreSQL listen on local sockets only, so the only open ports are 22, 80 and 443:

sudo ss -tlnp | awk 'NR==1 || /nginx|sshd|php|postgres/' | awk '{print $1, $4, $6}' | sed -E 's/,pid=[0-9]+,fd=[0-9]+//g'
State Local Peer
LISTEN 0.0.0.0:22 users:(("sshd"),("systemd"))
LISTEN 0.0.0.0:80 users:(("nginx"),("nginx"),("nginx"))
LISTEN 0.0.0.0:443 users:(("nginx"),("nginx"),("nginx"))
LISTEN [::]:22 users:(("sshd"),("systemd"))
LISTEN [::]:80 users:(("nginx"),("nginx"),("nginx"))
LISTEN [::]:443 users:(("nginx"),("nginx"),("nginx"))

The CDash release, PHP, PostgreSQL and how the image was built:

cat /var/www/cdash/public/VERSION
php -v | head -1
/usr/lib/postgresql/16/bin/postgres --version
sed -n '3,4p' /usr/share/doc/cdash/SOURCE.txt
v5.5.2
PHP 8.4.27 (cli) (built: Oct 21 2026 14:35:21) (NTS)
postgres (PostgreSQL) 16.15 (Ubuntu 16.15-0ubuntu0.24.04.1)
Upstream: the official CDash 5.5.2 release, GitHub tag v5.5.2 of https://github.com/Kitware/CDash
(commit 337d905ad927a4d7a42dd1320c30227a5472be8a), archive https://codeload.github.com/Kitware/CDash/tar.gz/refs/tags/v5.5.2 (sha256 8caac71176d7301e548d0d1c947dcac302ebea10cc366c221e3e6944c6107c3a).

/usr/share/doc/cdash/SOURCE.txt lists exactly how the release was built and what was left out, and /usr/share/doc/cdash/frontend-packages.txt lists the JavaScript packages compiled into CDash's pages.

Step 4: Get your sign-in details

The credentials file holds the address CDash is served as (your instance's public DNS name by default) and the administrator's e-mail and password, generated on this instance:

sudo cat /root/cdash-credentials.txt
CDASH_URL=https://ec2-<public-ip-dashed>.<region>.compute.amazonaws.com/
CDASH_ADMIN_EMAIL=admin@cloudimg.local
CDASH_ADMIN_PASSWORD=<24 letters and digits>

There is no database password: PostgreSQL accepts CDash's own system user over the local socket only.

Step 5: Sign in

Open CDASH_URL in your browser. The certificate is self-signed (generated on your instance), so your browser asks you to confirm the first time; Step 11 shows how to use your own DNS name and certificate. Sign in with the e-mail and password from the credentials file:

The CDash sign-in page with the e-mail and password fields

After you sign in, CDash shows its projects page. A fresh instance has no projects yet:

The CDash projects page of a fresh instance, signed in as the administrator

Open Profile (top left) to set your own name and e-mail address, and change the password from there or with sudo cdash-set-password (Step 12). The footer's GraphQL Explorer link leads to a page this image switches off (Step 8).

Step 6: Create a project

As the administrator, open /projects/new (or Administration, then Create new project), give it a name, choose who can see it and tick Authenticate submissions:

The CDash create-project form with a name, a description, private visibility and Authenticate submissions ticked

Then open Profile, then Authentication Tokens (or /authtokens/manage) and create a submit only token for the project. CDash shows the token once: store it in your CI system's secret store, never in the repository.

Step 7: Submit from CTest

In your project, add a CTestConfig.cmake next to the top-level CMakeLists.txt (the project name must match the one in CDash):

set(CTEST_PROJECT_NAME "<your-project>")
set(CTEST_NIGHTLY_START_TIME "01:00:00 UTC")
set(CTEST_SUBMIT_URL "https://<your-cdash-host>/submit.php?project=<your-project>")

and run a dashboard build with the token in an HTTP header (CTest 3.15 or later):

ctest -D Experimental --http-header "Authorization: Bearer <your-token>"

In a CTest script, set CTEST_SUBMIT_HTTP_HEADER or pass HTTPHEADER "Authorization: Bearer ${token}" to ctest_submit(). While the certificate is self-signed, either install it on your CI machines or add --tls-verify OFF only on a network you trust; with your own certificate (Step 11) nothing extra is needed. The configure output, warnings and errors and the test results appear on the project's dashboard within seconds; CDash's queue worker parses each submission in the background:

A CDash project dashboard with one Experimental build of linux-gcc-release on ci-runner-01: configure, build warning and test counts

The CDash build summary of linux-gcc-release with its configure, build and test results

The CDash test results of the build: three passed tests and one failed test with their timing

Your tokens are listed under Authentication Tokens, where you can revoke one at any time:

The CDash authentication tokens page listing the submit-only token of ci-runner-01

A submission without the token, or with a wrong one, is refused (403 Invalid Token). Submissions are capped at 256 MB each.

Step 8: The settings that are closed by default

CDash's settings live in /etc/cdash/cdash.env, which root owns and CDash can read but not change. The defaults this image sets:

sudo grep -E '^(APP_ENV|APP_DEBUG|QUEUE_CONNECTION|REQUIRE_AUTHENTICATED_SUBMISSIONS|USER_REGISTRATION_FORM_ENABLED|MINIMUM_PASSWORD_LENGTH|GRAPHIQL_ENABLED|USE_VCS_API|MAIL_MAILER|DB_HOST|DB_PASSWORD)=' /etc/cdash/cdash.env
APP_ENV=production
APP_DEBUG=false
DB_HOST=/var/run/postgresql
DB_PASSWORD=
QUEUE_CONNECTION=database
MAIL_MAILER=log
GRAPHIQL_ENABLED=false
REQUIRE_AUTHENTICATED_SUBMISSIONS=true
USER_REGISTRATION_FORM_ENABLED=false
MINIMUM_PASSWORD_LENGTH=12
USE_VCS_API=false
  • USE_VCS_API=false: CDash does not call GitHub or other repository APIs (commit details, pull-request comments) until you switch it on.
  • MAIL_MAILER=log: CDash writes e-mails to its log until you configure SMTP (Step 12); mail() is not available to PHP.
  • GRAPHIQL_ENABLED=false: the GraphQL explorer page is off. CDash's own pages use the GraphQL API at /graphql, which stays on.

After any change, rebuild CDash's caches (this also restarts nothing that is not needed):

sudo /usr/local/lib/cloudimg/cdash/rebuild-caches

Step 9: Your data

What Where
PostgreSQL 16 cluster (projects, builds, test results, users) /var/lib/postgresql/16/main
Submissions waiting for, being and already parsed; uploaded files /var/lib/cdash/storage/app
CDash's logs /var/lib/cdash/storage/logs
Settings /etc/cdash/cdash.env
The code (read only to CDash) /var/www/cdash

Back up the database with pg_dump as the postgres user and copy /var/lib/cdash/storage/app/upload and /etc/cdash/cdash.env (it holds the application key, which signs sessions and stored tokens):

sudo -u postgres pg_dump -h /var/run/postgresql -Fc cdash > cdash-$(date +%F).dump

Step 10: Security checks

Port 80 sends browsers to HTTPS, the health endpoint answers for load balancer checks, and the old password-recovery page, the GraphQL explorer, the settings file, the code and the logs are not reachable:

H=$(sed -n 's/^set \$cd_host "\(.*\)";$/\1/p' /etc/nginx/cdash-host.conf)
curl -s -o /dev/null -w 'port 80: %{http_code} -> %{redirect_url}\n' --resolve "$H:80:127.0.0.1" "http://$H/login" | sed -E 's#https://[^/]+#https://<your host>#'
curl -sk --resolve "$H:443:127.0.0.1" "https://$H/healthz"
for p in /recoverPassword.php /graphql/explorer /.env /composer.json /vendor/autoload.php /storage/logs/cdash.log /register; do
  curl -sk -o /dev/null -w "$p: %{http_code}\n" -H 'Sec-Fetch-Site: same-origin' --resolve "$H:443:127.0.0.1" "https://$H$p"
done
curl -s -o /dev/null -w 'unknown host name: %{http_code}\n' -H 'Host: example.com' http://127.0.0.1/ || true
port 80: 301 -> https://<your host>/login
ok
/recoverPassword.php: 404
/graphql/explorer: 404
/.env: 404
/composer.json: 404
/vendor/autoload.php: 404
/storage/logs/cdash.log: 404
/register: 404
unknown host name: 000

(000 means nginx closed the connection without an answer.) A request that changes something is refused when it comes from another site, and CTest's submission endpoint answers only in its exact form (here for a project that does not exist):

H=$(sed -n 's/^set \$cd_host "\(.*\)";$/\1/p' /etc/nginx/cdash-host.conf)
curl -sk -o /dev/null -w 'cross-site POST /api/v1/buildgroup.php: %{http_code}\n' -X POST -H 'Origin: https://example.com' --data 'x=1' --resolve "$H:443:127.0.0.1" "https://$H/api/v1/buildgroup.php"
curl -sk -o /dev/null -w 'cross-site POST /graphql: %{http_code}\n' -X POST -H 'Sec-Fetch-Site: cross-site' --data '{}' --resolve "$H:443:127.0.0.1" "https://$H/graphql"
curl -sk -o /dev/null -w 'PUT /submit.php: %{http_code}\n' -X PUT --data-binary 'x' --resolve "$H:443:127.0.0.1" "https://$H/submit.php?project=no-such-project"
curl -sk -o /dev/null -w 'PUT /SUBMIT.php: %{http_code}\n' -X PUT --data-binary 'x' --resolve "$H:443:127.0.0.1" "https://$H/SUBMIT.php?project=no-such-project"
cross-site POST /api/v1/buildgroup.php: 403
cross-site POST /graphql: 403
PUT /submit.php: 404
PUT /SUBMIT.php: 403

The credentials and settings files, the code and CDash's folders:

sudo stat -c '%a %U:%G %n' /root/cdash-credentials.txt /etc/cdash /etc/cdash/cdash.env /var/www/cdash /var/lib/cdash /var/lib/cdash/storage
600 root:root /root/cdash-credentials.txt
750 root:cdash /etc/cdash
640 root:cdash /etc/cdash/cdash.env
755 root:root /var/www/cdash
750 root:cdash /var/lib/cdash
750 cdash:cdash /var/lib/cdash/storage

PostgreSQL has no network listener, only local peer authentication, and CDash's database role has no password and no privileges outside its database:

sudo -u postgres psql -X -tA -h /var/run/postgresql -d postgres -c "SHOW listen_addresses" -c "SELECT rolname, rolsuper, rolpassword IS NULL AS no_password FROM pg_authid WHERE rolname = 'cdash'"
sudo grep -vE '^[[:space:]]*(#|$)' /etc/postgresql/16/main/pg_hba.conf

cdash|f|t
local   all     postgres                peer
local   cdash   cdash                   peer

(The empty first line is listen_addresses: no TCP listener.) PHP's restrictions are in effect for the web server and the background services, and both are denied the metadata service and internal addresses:

grep -E '^php_admin_value\[(disable_functions|ffi.enable)\]' /etc/php/8.4/fpm/pool.d/cdash.conf
for u in php8.4-fpm cdash-worker; do echo "$u: $(systemctl show -p IPAddressDeny --value $u | tr ' ' '\n' | grep -cE '^(127\.0\.0\.0/8|10\.0\.0\.0/8|169\.254\.0\.0/16|172\.16\.0\.0/12|192\.168\.0\.0/16|::1/128|fc00::/7)$') of 7 internal ranges denied"; done
php_admin_value[disable_functions] = exec,passthru,shell_exec,system,proc_open,popen,pcntl_exec,pcntl_fork,putenv,mail,dl,imap_open
php_admin_value[ffi.enable] = 0
php8.4-fpm: 7 of 7 internal ranges denied
cdash-worker: 7 of 7 internal ranges denied

Step 11: Your own DNS name and certificate

Point a DNS name at the instance, then tell CDash to use it. This generates a new self-signed certificate for the name, pins nginx to it and updates CDash's address:

sudo cdash-set-hostname cdash.example.com

For a trusted certificate, install certbot with the nginx plugin, request a certificate for the name and keep nginx's ssl_certificate lines in /etc/nginx/sites-available/cloudimg-cdash pointing at it. Once a trusted certificate is in place, you can also add a Strict-Transport-Security header in that file. Re-run cdash-set-hostname whenever the name changes.

Step 12: Passwords, users, e-mail, LDAP and upgrades

  • Administrator password: sudo cdash-set-password generates a new one, signs every session out and records it in /root/cdash-credentials.txt.
  • Users: as the administrator open Users to add accounts, or set USER_REGISTRATION_FORM_ENABLED=true in /etc/cdash/cdash.env if you want people to register themselves.
  • E-mail: set MAIL_MAILER=smtp and MAIL_HOST, MAIL_PORT, MAIL_USERNAME, MAIL_PASSWORD, MAIL_ENCRYPTION and MAIL_FROM_ADDRESS in /etc/cdash/cdash.env, then run rebuild-caches and sudo cdash-artisan email:test --email=you@example.com. CDash's password reset by e-mail (Laravel's, under Forgot your password? on recent releases) works once mail does.
  • A server inside your VPC (SMTP relay, LDAP, GitHub Enterprise): CDash may not connect to private addresses by default. Allow exactly that address for PHP and the worker with a drop-in, for example for an LDAP server at 10.0.1.25:
for u in php8.4-fpm cdash-worker cdash-scheduler; do
  sudo mkdir -p /etc/systemd/system/$u.service.d
  printf '[Service]\nIPAddressAllow=10.0.1.25/32\n' | sudo tee /etc/systemd/system/$u.service.d/70-allow-ldap.conf
done
sudo systemctl daemon-reload && sudo systemctl restart php8.4-fpm cdash-worker cdash-scheduler
  • GitHub integration: set USE_VCS_API=true and the GITHUB_* settings, and set GITHUB_WEBHOOK_SECRET. The webhook endpoint /api/v1/GitHub/webhook.php is refused by the cross-site guard until you exempt it in /etc/nginx/conf.d/cloudimg-cdash.conf (add its exact path next to /submit.php in the $cd_submit_raw and $cd_submit_norm maps).
  • Artisan: run CDash's commands as sudo cdash-artisan <command> (for example queue:failed or project:delete <name>). Never put a password on its command line; it refuses --password.
  • Upgrades: Ubuntu and PHP security updates install automatically. A new CDash release replaces /var/www/cdash: cloudimg publishes new versions in this listing; to upgrade in place, follow CDash's upgrade notes, build the release the same way (SOURCE.txt) and run sudo cdash-artisan migrate --force.

Step 13: Server components

Component Version
CDash 5.5.2
PHP 8.4 (ondrej/php PPA), PHP-FPM as user cdash
PostgreSQL 16 (Ubuntu 24.04)
nginx 1.24 (Ubuntu 24.04)
Operating system Ubuntu 24.04 LTS
Service Purpose
nginx HTTPS on 443, redirect on 80
php8.4-fpm CDash's web pages and API
postgresql@16-main the database (local socket only)
cdash-worker parses submissions and runs CDash's background jobs
cdash-scheduler runs CDash's scheduled pruning and notification jobs every minute
cdash-firstboot creates this instance's database, keys, password and certificate (once)

Step 14: Security recommendations

  • Restrict port 443 to your team and CI networks unless your projects are meant to be public.
  • Tick Authenticate submissions on every project and use submit-only tokens for CI; revoke tokens you no longer use.
  • Use your own DNS name and a trusted certificate (Step 11), then add HSTS.
  • Keep AWS backups of the EBS volume, or regular pg_dump backups (Step 9).
  • The front end of CDash 5.5.2 still includes AngularJS 1.8.3 for its older pages; AngularJS is no longer maintained upstream. The two high-severity AngularJS advisories (CVE-2024-21490 and CVE-2026-11998) apply to features CDash does not use (ng-srcset and custom resource-URL allow lists).

Support and licensing

CDash is open source software by Kitware, released under the BSD 3-Clause licence (/usr/share/doc/cdash/LICENSE). cloudimg provides the image, its hardening and support for launching and running it; contact support@cloudimg.co.uk. CDash's own documentation is at https://github.com/Kitware/CDash/tree/master/docs.