Kiwi TCMS Test Case Management on AWS User Guide
Overview
Kiwi TCMS is a mature, open source test case management system used by QA and engineering teams to plan, organise and track manual and automated testing. It manages products, test plans, test cases, test runs and executions, tracks requirements and history, integrates with bug trackers, and exposes a full REST/JSON-RPC API for automation. The cloudimg image runs the official Kiwi TCMS Docker Compose stack (the Kiwi web application plus a MariaDB database) behind host nginx, which terminates TLS on port 443 with a per-instance self-signed certificate. Every application secret, the database passwords, the TLS certificate and a strong administrator account are generated uniquely on the first boot of each instance, so no shared or default credential ever ships in the image, and public self-registration is disabled. Built from Kiwi TCMS 16.2 (GPL-2.0), backed by 24/7 cloudimg support.
What is included:
- Kiwi TCMS 16.2 as the official Docker Compose stack: the Kiwi web application (Django + Apache/mod_wsgi) and a MariaDB 11.4 database
- Host nginx terminating TLS on port 443 with a per-instance self-signed certificate; plain HTTP on port 80 redirects to HTTPS
- The database on the internal container network only, with no externally reachable port
- The stack managed by a single
kiwi-tcms.servicesystemd unit, enabled and active on every boot - All stateful Docker volumes (the MariaDB database and uploads) relocated onto a dedicated EBS data volume mounted at
/var/lib/kiwi-tcms - A first-boot service that generates a fresh Django secret key, database passwords, a per-instance TLS certificate and a strong administrator account, and records the admin credentials in a root-only file
- 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. Security group inbound: allow 22/tcp from your management network and 443/tcp (and 80/tcp, which redirects to HTTPS) for the web console. The image serves the console over HTTPS on port 443 using a per-instance self-signed certificate; for production, replace it with a certificate for your own domain.
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, 80 and 443.
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=kiwi-tcms}]'
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
Kiwi TCMS runs as a Docker Compose stack wrapped by a single systemd unit, fronted by nginx, with a one-shot first-boot service that rotates every secret on the first boot. Confirm they are healthy:
systemctl is-active docker.service nginx.service kiwi-tcms.service kiwi-tcms-firstboot.service
All four report active (kiwi-tcms-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 Kiwi TCMS appliance:
sudo docker compose -f /opt/kiwi-tcms/compose.yaml --env-file /opt/kiwi-tcms/.env ps --format 'table {{.Service}}\t{{.Status}}'
You will see web and db both Up (the db container reports healthy). The web container publishes its HTTPS port on 127.0.0.1:8443 only; nginx on the host is the single public front door.
Step 5 - Confirm the version and endpoints
Check the running Kiwi TCMS version and that the web endpoints answer through nginx:
sudo docker compose -f /opt/kiwi-tcms/compose.yaml --env-file /opt/kiwi-tcms/.env exec -T web python -c 'import tcms; print("Kiwi TCMS", tcms.__version__)'
curl -ks -o /dev/null -w 'login page: HTTP %{http_code}\n' https://127.0.0.1/accounts/login/
curl -s -o /dev/null -w 'HTTP redirect: HTTP %{http_code}\n' http://127.0.0.1/
The version reads Kiwi TCMS 16.2, the login page returns 200 over HTTPS, and plain HTTP returns 301 (redirecting to HTTPS). The login page is unauthenticated and makes a convenient load-balancer health check.
Step 6 - The data volume
The MariaDB database and the uploads live on a dedicated EBS data volume mounted at /var/lib/kiwi-tcms, separate from the OS disk, where the Docker data-root has been relocated:
findmnt -no SOURCE,TARGET,FSTYPE /var/lib/kiwi-tcms
It reports an ext4 filesystem mounted at /var/lib/kiwi-tcms. 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 account for this instance and wrote it to a root-only credentials file. Read the URL and username (the password is on the KIWI_ADMIN_PASSWORD= line):
sudo stat -c '%a %U:%G %n' /root/kiwi-tcms-credentials.txt
sudo grep -E '^KIWI_(URL|ADMIN_USER)=' /root/kiwi-tcms-credentials.txt
The file is 600 root:root. To display the generated password, run sudo grep '^KIWI_ADMIN_PASSWORD=' /root/kiwi-tcms-credentials.txt.
Step 8 - Prove the admin credential end to end
Confirm the generated administrator credential authenticates against the login form through nginx, and that a wrong password is rejected. The password is read into a shell variable and never printed; only the HTTP status is shown (302 on success, 200 when the login form is re-rendered after a rejected attempt):
USER="$(sudo grep '^KIWI_ADMIN_USER=' /root/kiwi-tcms-credentials.txt | cut -d= -f2-)"
PASS="$(sudo grep '^KIWI_ADMIN_PASSWORD=' /root/kiwi-tcms-credentials.txt | cut -d= -f2-)"
JAR="$(mktemp)"
CSRF="$(curl -ks -c "$JAR" https://127.0.0.1/accounts/login/ | grep -oE 'name="csrfmiddlewaretoken"[^>]*value="[^"]+"' | grep -oE 'value="[^"]+"' | head -1 | sed 's/value="//;s/"//')"
curl -ks -o /dev/null -w 'valid login: HTTP %{http_code}\n' -b "$JAR" -c "$JAR" -H "Referer: https://127.0.0.1/accounts/login/" -X POST https://127.0.0.1/accounts/login/ --data-urlencode "csrfmiddlewaretoken=$CSRF" --data-urlencode "username=$USER" --data-urlencode "password=$PASS"
curl -ks -o /dev/null -w 'wrong login: HTTP %{http_code}\n' -b "$JAR" -H "Referer: https://127.0.0.1/accounts/login/" -X POST https://127.0.0.1/accounts/login/ --data-urlencode "csrfmiddlewaretoken=$CSRF" --data-urlencode "username=$USER" --data-urlencode "password=wrong-pass-xyz"
rm -f "$JAR"
The valid credential returns 302 (a successful login redirect) and the wrong password returns 200 (the login form re-rendered with an error).
Step 9 - The database is private
The MariaDB database runs on the internal container network only, with no host-published port, so it is never reachable from outside the instance. Confirm nothing is listening on 3306 on any host address:
sudo ss -ltnH | awk '{print $4}' | grep -E ':3306$' || echo '3306 is not listening on any host address'
Step 10 - Sign in to the console
Browse to https://<instance-public-ip>/ in any modern browser. The image ships a per-instance self-signed certificate, so accept the browser warning (or install a certificate for your own domain). Sign in with the username and password from Step 7.

Step 11 - The dashboard
After signing in you land on the dashboard: your recent test executions with completion bars, and the test plans you manage. On a fresh instance these start empty and populate as you create products, plans, cases and runs.

Step 12 - Test plans and test cases
Kiwi TCMS organises testing into products, test plans and test cases. Create a product under TESTING -> Products, add a version, then create a test plan for it and add test cases. Each case captures a summary, steps, priority, category and status, and can be automated or manual.

Step 13 - Test runs and executions
A test run executes a plan's cases against a build. Create a run, then record each case as passed, failed, blocked or waived; the run's completion bar and per-status counts update as you go, giving you a live picture of coverage and results.

Step 14 - Automate with the API
Kiwi TCMS exposes a JSON-RPC API at /json-rpc/ for submitting results from your CI/CD pipeline and scripting any object the UI manages (products, plans, cases, runs and executions). Authenticate with your administrator credentials, then call methods such as TestCase.filter, TestRun.create and TestExecution.update. See the Kiwi TCMS API documentation for the full method list. Example (replace the host and password):
curl -s -c cookies.txt https://<instance-public-ip>/accounts/login/ # obtain a CSRF cookie
# then POST to /json-rpc/ with your session, calling e.g. TestCase.filter({})
Step 15 - Configure email notifications (optional)
Kiwi TCMS can email notifications (for example when a test case a user follows changes). Out of the box no SMTP server is configured, so notifications are silently skipped and never block any action. To enable them, configure your SMTP settings in the Kiwi TCMS environment and restart the stack:
sudo docker compose -f /opt/kiwi-tcms/compose.yaml --env-file /opt/kiwi-tcms/.env restart web
Support
Every cloudimg image is backed by 24/7 support. Our engineers can help with deployment, replacing the self-signed certificate with one for your own domain, bug-tracker and API integration, backup and storage planning, and scaling the stack. Contact support through the AWS Marketplace listing or the cloudimg website.
All product and company names are trademarks or registered trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.