Security AWS

DefectDojo Vulnerability Management on AWS User Guide

| Product: DefectDojo

Overview

DefectDojo is an open source, OWASP flagship DevSecOps and application vulnerability management platform. It consolidates the output of hundreds of security scanners, deduplicates and triages findings, tracks remediation across products and engagements, and reports on your security posture over time. The cloudimg image runs the official DefectDojo production Docker Compose stack behind nginx on port 80, with the database, cache and uploads on a dedicated data volume. A strong administrator password and every application secret are generated uniquely on the first boot of each instance, so no shared or default credential ever ships in the image. Built from DefectDojo 3.0.100 (BSD-3-Clause), backed by 24/7 cloudimg support.

What is included:

  • DefectDojo 3.0.100 as the official Docker Compose stack: nginx, the uwsgi Django app, celery worker and beat, PostgreSQL and Valkey (Redis compatible)
  • The whole stack managed by a single defectdojo.service systemd unit, enabled and active on every boot
  • All stateful Docker volumes (database, cache, media and uploads) relocated onto a dedicated EBS data volume mounted at /var/lib/defectdojo
  • A first-boot service that generates a fresh Django secret key, credential encryption key, database password and a strong per-instance admin password, and records the admin credentials in a root-only file
  • The unauthenticated login page doubling as a health endpoint, and a full REST API for automation
  • 24/7 cloudimg support

Prerequisites

An AWS account, an EC2 key pair in the target region, and a VPC with a public subnet. m5.large (2 vCPU / 8 GiB RAM) is the recommended instance type; DefectDojo runs several containers, so 8 GiB RAM or more is advised. Security group inbound: allow 22/tcp from your management network and 80/tcp (and 443/tcp if you terminate TLS) for the web console. DefectDojo serves plain HTTP on port 80; for production, terminate TLS in front of it with your own domain so the console runs over HTTPS.

Step 1 - Launch the AMI

Subscribe to the listing in AWS Marketplace, choose Continue to Launch, and launch through the EC2 console or the AWS CLI. Select the m5.large instance type, your key pair, and a security group that opens ports 22 and 80 (and 443 for TLS).

aws ec2 run-instances \
  --image-id <ami-id> \
  --instance-type m5.large \
  --key-name <your-key-pair> \
  --security-group-ids <security-group-id> \
  --subnet-id <subnet-id> \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=defectdojo}]'

Step 2 - Connect to your instance

Connect over SSH as the default login user for the OS variant you launched. This listing may ship more than one OS variant; use the matching login user below.

OS variant SSH login user Connect
Ubuntu 24.04 LTS ubuntu ssh ubuntu@<instance-public-ip>

Step 3 - Confirm the stack is running

DefectDojo runs as a Docker Compose stack wrapped by a single systemd unit, with a one-shot first-boot service that rotates every secret on the first boot. Confirm they are healthy:

systemctl is-active docker.service defectdojo.service defectdojo-firstboot.service

All three report active (defectdojo-firstboot.service is a one-shot that remains active after it has completed).

Step 4 - Inspect the Compose stack

List the containers that make up the DefectDojo appliance:

sudo docker compose -f /opt/defectdojo/docker-compose.yml -f /opt/defectdojo/docker-compose.override.cloudimg.yml --env-file /opt/defectdojo/.env ps --format 'table {{.Service}}\t{{.Status}}'

You will see nginx, uwsgi, celerybeat, celeryworker, postgres and valkey all Up. nginx publishes the console on host port 80.

Step 5 - Confirm the version and endpoints

Check the running DefectDojo version and that the web endpoints answer:

sudo docker compose -f /opt/defectdojo/docker-compose.yml -f /opt/defectdojo/docker-compose.override.cloudimg.yml --env-file /opt/defectdojo/.env exec -T uwsgi grep -m1 __version__ dojo/__init__.py
curl -s -o /dev/null -w 'login page: HTTP %{http_code}\n' http://127.0.0.1/login
curl -s -o /dev/null -w 'REST API:   HTTP %{http_code}\n' http://127.0.0.1/api/v2/

The version reads __version__ = "3.0.100" and the login page returns 200. The login page is unauthenticated and makes a convenient load-balancer health check.

Step 6 - The data volume

The database, cache and uploads live on a dedicated EBS data volume mounted at /var/lib/defectdojo, separate from the OS disk, where the Docker data-root has been relocated:

findmnt -no SOURCE,TARGET,FSTYPE /var/lib/defectdojo

It reports an ext4 filesystem mounted at /var/lib/defectdojo. Back up that volume (for example with an EBS snapshot) to preserve your database and uploads.

Step 7 - Retrieve the per-instance admin credentials

The first-boot service generated a unique administrator password for this instance and wrote it, with every rotated secret kept out of the file, to a root-only credentials file. Read the URL and username (the password is on the defectdojo.admin.pass= line):

sudo stat -c '%a %U:%G %n' /root/defectdojo-credentials.txt
sudo grep -E '^defectdojo\.(url|admin\.user)=' /root/defectdojo-credentials.txt

The file is 600 root:root. To display the generated password, run sudo grep '^defectdojo.admin.pass=' /root/defectdojo-credentials.txt.

Step 8 - Prove the admin credential end to end

Confirm the generated administrator credential authenticates against the REST API and returns a token (a wrong password is rejected):

PASS="$(sudo grep '^defectdojo.admin.pass=' /root/defectdojo-credentials.txt | cut -d= -f2-)"
curl -s -o /dev/null -w 'valid password:   HTTP %{http_code}\n' -X POST http://127.0.0.1/api/v2/api-token-auth/ -H 'Content-Type: application/json' -d "{\"username\":\"admin\",\"password\":\"$PASS\"}"
curl -s -o /dev/null -w 'wrong password:   HTTP %{http_code}\n' -X POST http://127.0.0.1/api/v2/api-token-auth/ -H 'Content-Type: application/json' -d '{"username":"admin","password":"wrong-pass-xyz"}'

The valid password returns 200 (with a token in the body), and the wrong password returns 400.

Step 9 - Sign in to the console

Browse to http://<instance-public-ip>/ in any modern browser (or use your own HTTPS domain in production). Sign in as admin with the password from Step 7.

The DefectDojo sign-in page served behind nginx

Step 10 - The dashboard

After signing in you land on the dashboard: KPI tiles for active engagements and recent findings, plus the historical finding severity breakdown and reported severity by month. On a fresh instance these start empty and populate as you import findings.

The DefectDojo dashboard with KPI tiles and the finding severity charts

Step 11 - Import scanner findings

DefectDojo organises work into products, engagements and tests, and understands the output of a very wide range of scanners. You can import from the UI (Engagements -> Import Scan Results) or via the REST API. The example below creates a product and engagement on the fly and imports a Generic Findings Import file using the API token:

TOKEN=$(curl -s -X POST http://<instance-public-ip>/api/v2/api-token-auth/ \
  -H 'Content-Type: application/json' \
  -d '{"username":"admin","password":"<password from Step 7>"}' | jq -r .token)

curl -s -X POST http://<instance-public-ip>/api/v2/import-scan/ \
  -H "Authorization: Token $TOKEN" \
  -F 'scan_type=Generic Findings Import' \
  -F 'product_name=Acme Storefront' \
  -F 'engagement_name=Q3 2026 Application Assessment' \
  -F 'auto_create_context=true' \
  -F 'active=true' -F 'verified=true' \
  -F 'file=@findings.json;type=application/json'

Step 12 - Triage findings

Imported findings appear under Findings, deduplicated and tagged with severity, CWE, SLA age and the tool that reported them. Sort and filter to triage: accept risk, assign owners, mark as mitigated, or bulk-update.

The open findings list with severity, CWE and SLA columns

Step 13 - Track a product

Each product has an overview page with a severity metrics breakdown, its SLA configuration, and tabs for engagements, findings, components and endpoints, so you can see the security posture of one application at a glance.

A product overview page with the severity metrics breakdown and SLA configuration

Maintenance

  • Data: the PostgreSQL database, Valkey cache and all uploads live under /var/lib/defectdojo on the dedicated data volume. Back it up with an EBS snapshot to preserve your findings and history.
  • Stack control: the whole appliance is one systemd unit. Use sudo systemctl restart defectdojo.service to bounce it, or the underlying sudo docker compose -f /opt/defectdojo/docker-compose.yml -f /opt/defectdojo/docker-compose.override.cloudimg.yml --env-file /opt/defectdojo/.env <command> for finer control.
  • Credentials: the per-instance admin password is in /root/defectdojo-credentials.txt. Change it from the DefectDojo UI (Profile -> Change Password) after first sign-in for day-to-day use.
  • TLS: DefectDojo serves plain HTTP on port 80. Front it with TLS and your own domain before production use so the console runs over HTTPS; DD_ALLOWED_HOSTS is set to * so any hostname is accepted out of the box.
  • Upgrades and pinning: the stack is pinned to the 3.0.100 published images via DJANGO_VERSION / NGINX_VERSION in /opt/defectdojo/.env, so it never silently upgrades.
  • Security patches: unattended-upgrades remains enabled so the OS continues to receive security updates automatically.

Support

cloudimg provides 24/7 expert support for this image. Contact support@cloudimg.co.uk.

This image packages the open source DefectDojo software (BSD-3-Clause License) for convenient deployment on AWS. cloudimg is not affiliated with, endorsed by, or sponsored by the DefectDojo project or OWASP.