Deployment guide

CDash 5.5.2

Overview

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. CDash shows them per project, build group and machine, with history, test timing, filters, e-mail notifications and an API.

This SecureAnyCloud AMI runs CDash 5.5.2 on Ubuntu 24.04 on Amazon EC2. It is one version of the SecureAnyCloud Hardened Apache Subversion (SVN) & CI/CD Tools listing on AWS Marketplace. You choose it as the software version when you subscribe and launch.

What you get:

  • 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 first boot 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. 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 that the instance does not serve are dropped.
  • Token-authenticated CTest submissions. CDash is set to require authenticated submissions. Every project that 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, and you add users yourself. 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. For that reason, the image does not serve the page. 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. The project tokens protect that endpoint 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, PHP 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. 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, uploaded build files and every other response that is not one of CDash's own HTML pages are served with a sandboxing content security policy, in every spelling of their address, so no script in submitted content runs 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. PHP 8.4 therefore comes from the ondrej/php PPA, which is trusted only through its pinned signing key and allowed to provide PHP packages only. Unattended upgrades keep it patched along with Ubuntu.
  • A fully patched base. Ubuntu 24.04 LTS is patched 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. These are your team's browsers and every machine that runs CTest. Keep port 22 open to your own networks only.
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, select your Region, and choose Launch through EC2.

Choose m5.large (or larger for many projects or large submissions), your key pair and a security group as described in Prerequisites.

To launch with the AWS CLI instead, 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}]'
2

Connect to your instance

Connect over SSH as the login user for the version you launched:

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

Check the services

First boot takes under a minute. Afterwards, nginx, PHP, PostgreSQL, CDash's queue worker and scheduler, and the first-boot unit should be 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"))

These commands show 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. /usr/share/doc/cdash/frontend-packages.txt lists the JavaScript packages compiled into CDash's pages.

4

Get your sign-in details

The credentials file holds the address that 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@sac.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.

5

Sign in

Open CDASH_URL in your browser. The certificate is self-signed and was 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:

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

Open Profile (top left) to set your own name and e-mail address. Change the password from there or with sudo cdash-set-password (Step 12).

The footer's GraphQL Explorer link leads to a page that this image switches off (Step 8).

6

Create a project

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

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.

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>")

Then 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, and 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:

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

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

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 image sets these defaults:

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= <set-at-first-boot>=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), and 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/sac/cdash/rebuild-caches
9

Your data

CDash keeps its data in these locations:

  • PostgreSQL 16 cluster (projects, builds, test results, users): /var/lib/postgresql/16/main
  • Submissions waiting to be parsed, being parsed and already parsed, plus 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. Also copy /var/lib/cdash/storage/app/upload and /etc/cdash/cdash.env. The settings file 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
10

Security checks

Port 80 sends browsers to HTTPS, and the health endpoint answers for load balancer checks. The following are not reachable: the old password-recovery page, any path after index.php (which CDash's framework would otherwise route like the plain path, past nginx's rules), the GraphQL explorer, the settings file, the code and the logs.

Run:

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 /index.php/recoverPassword.php /index.php/login /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 /index.php/recoverPassword.php: 404 /index.php/login: 404 /graphql/explorer: 404 /.env: 404 /composer.json: 404 /vendor/autoload.php: 404 /storage/logs/cdash.log: 404 /register: 404 unknown host name: 000

A status of 000 means that 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

Check 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 and uses only local peer authentication. 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, which means 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
11

Your own DNS name and certificate

Point a DNS name at the instance, then tell CDash to use it. This command 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 and request a certificate for the name. Keep nginx's ssl_certificate lines in /etc/nginx/sites-available/sac-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.

12

Passwords, users, e-mail, LDAP and upgrades

  • Administrator password: sudo cdash-set-password generates a new password, signs every session out and records the password 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 works.
  • 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. This example allows 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, the GITHUB_* settings and 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/sac-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. The wrapper refuses --password.
  • Upgrades: Ubuntu and PHP security updates install automatically. A new CDash release replaces /var/www/cdash. SecureAnyCloud 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.
13

Server components

The image runs these components:

  • CDash 5.5.2
  • PHP 8.4 (ondrej/php PPA), with PHP-FPM running as user cdash
  • PostgreSQL 16 (Ubuntu 24.04)
  • nginx 1.24 (Ubuntu 24.04)
  • Operating system: Ubuntu 24.04 LTS

These services make up the stack:

  • 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)
14

Security recommendations

  • Restrict port 443 to your team and CI networks unless your projects are meant to be public.
  • Select Authenticate submissions on every project, use submit-only tokens for CI, and 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 take regular pg_dump backups (Step 9).
  • The front end of CDash 5.5.2 still includes AngularJS 1.8.3 for its older pages, and 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).

SecureAnyCloud provides the image, its hardening and support for launching and running it. Contact sales@secureanycloud.com for help. CDash's own documentation is at https://github.com/Kitware/CDash/tree/master/docs.

Deploy on AWS

Launch CDash 5.5.2 on Ubuntu 24.04 on AWS with 24/7 support from SecureAnyCloud.

View on Marketplace

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on AWS