T1
Applications AWS

TCExam 17.3.1 on AWS User Guide

| Product: TCExam 17.3.1 on Ubuntu 24.04 on AWS

Overview

This guide covers launching and using TCExam 17.3.1 on Ubuntu 24.04 from cloudimg on Amazon EC2. It is one version of the cloudimg Hardened Moodle & E-Learning Platforms AMIs listing on AWS Marketplace; you pick it as the software version when you subscribe and launch. The other learning platforms in the listing are described on the listing's guide hub.

TCExam is a free and open source computer-based assessment (CBA) platform for schools, universities, training providers and certification bodies. You build a question bank (modules, subjects and questions of several types, with images and other media), assemble tests that draw questions from it, schedule them for groups of candidates, deliver them in a browser and review results, statistics and PDF reports. TCExam is free software distributed under the GNU Affero General Public License v3.0 or later. The TCExam name and logo are trademarks of Tecnick.com LTD; cloudimg is not affiliated with, endorsed by, or sponsored by Tecnick.com LTD. This image packages the unmodified upstream release together with cloudimg's provisioning, hardening and support.

What is included:

  • TCExam 17.3.1 in /var/www/tcexam, with its PDF fonts pre-built
  • PHP 8.3 (PHP-FPM) behind nginx at https://<instance-address>/; port 80 only redirects to HTTPS
  • A local MariaDB 10.11 database, bound to 127.0.0.1, which TCExam reaches over the local socket with no password
  • A per-instance administrator password, application salt and HTTPS certificate, all generated on first boot. No default, shared or published credential ships in the image
  • A small sample question bank and a Sample Quiz so you can see a working test straight away (edit or delete them)
  • 24/7 cloudimg support

Security posture

  • No default login. Upstream TCExam seeds the administrator admin with the password 1234. On this image the database does not exist until first boot, and first boot replaces that password with a unique per-instance one before the web tier is reachable. nginx and PHP-FPM stay stopped behind a bootstrap gate until the database is built, the password is rotated and admin / 1234 (and other guessable passwords) are proven refused.
  • No database password. TCExam connects to MariaDB as the system user www-data over the local socket (MariaDB unix_socket authentication), so there is no database password in the image or on any instance. MariaDB listens only on 127.0.0.1.
  • Per-instance application salt. TCExam signs result-access and CSRF tokens with K_RANDOM_SECURITY. The image ships TCExam's placeholder (on which TCExam fails closed) and first boot writes a unique value for this instance.
  • The image ships un-bootstrapped. The captured image contains an empty MariaDB datadir. First boot creates the tcexam database from TCExam's own schema files plus the sample bank. The web and command-line installers (install/) are removed from the image.
  • Self-registration and password reset are off. Upstream TCExam enables self-registration and e-mail password reset. This image turns both off, so a fresh instance never lets strangers create accounts. Enable them deliberately when you need them (Step 10).
  • Uploads never execute. TCExam 17.3 stores uploaded question media in cache/. nginx serves that directory as passive content, exactly as TCExam's own cache/.htaccess describes for Apache: any script (.php, .phtml, .phar, .cgi, .py and so on) is refused with 403 and never runs, HTML/XML/JavaScript/SVG files are sent as downloads, and every response carries X-Content-Type-Options: nosniff and a sandboxing Content-Security-Policy. TCExam itself also rejects script uploads and SVG files containing scripts.
  • Only TCExam's pages run. nginx executes only the TCExam entry points under /admin/code/ and /public/code/. Configuration, libraries, vendor/, logs and backups cannot be fetched over the web.
  • HTTPS from first boot, host from configuration. nginx serves TCExam on port 443 with a per-instance self-signed certificate; port 80 returns a 301 redirect to HTTPS. TCExam's base URL (K_PATH_HOST, used for every link it builds) is set from configuration (your DNS name, or the EC2 public name), never from a browser's Host header, and requests for any other host name are refused.
  • Client IP from the socket. TCExam keys sessions, test IP restrictions and test logs on the client address. nginx gives PHP the real connecting address and drops client-supplied X-Forwarded-For, X-Real-IP, Client-IP and Forwarded headers.
  • No instance-metadata access for the application. nginx, PHP-FPM, MariaDB and the first-boot unit are denied the EC2 metadata endpoint (169.254.169.254) by systemd.
  • Audited PHP libraries. Upstream ships no composer.lock, so cloudimg resolved one, audited it (no known advisories) and installs exactly that set. The build fails if the installed libraries differ from the audited lock or if composer audit reports anything. The TCPDF demo signing certificate and its private key are removed (PDF signing is off by default).

Step 1: Launch from AWS Marketplace

Subscribe to the Hardened Moodle & E-Learning Platforms AMIs listing, choose TCExam 17.3.1 on Ubuntu 24.04 as the software version, and launch. Recommended instance type: m5.large (2 vCPU, 8 GiB). For large simultaneous exam sessions choose a bigger instance. In the security group open TCP 22 (SSH, your own address only), TCP 80 and TCP 443. Do not open 3306; MariaDB is loopback only.

Step 2: Launch from the AWS CLI

aws ec2 run-instances \
  --image-id <ami-id-from-the-listing> \
  --instance-type m5.large \
  --key-name <your-key> \
  --security-group-ids sg-xxxxxxxx \
  --subnet-id subnet-xxxxxxxx \
  --associate-public-ip-address \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=tcexam}]'

First boot builds the database and provisions the per-instance credentials. Allow a minute or two before the site answers.

Step 3: Connect over SSH

OS variant SSH login user
Ubuntu 24.04 ubuntu
ssh -i /path/to/your-key.pem ubuntu@<instance-address>

Step 4: Retrieve your credentials

The per-instance administrator password is written to a root-only file on first boot:

sudo cat /root/tcexam-credentials.txt

The file gives the administration and candidate URLs, the administrator user (admin) and its per-instance password:

TCEXAM_ADMIN_URL=https://ec2-44-206-235-9.compute-1.amazonaws.com/admin/code/
TCEXAM_PUBLIC_URL=https://ec2-44-206-235-9.compute-1.amazonaws.com/public/code/
TCEXAM_ADMIN_USER=admin
TCEXAM_ADMIN_PASSWORD=<TCEXAM_ADMIN_PASSWORD>

Step 5: Verify the services

systemctl is-active mariadb php8.3-fpm nginx
curl -sk -o /dev/null -w '%{http_code}\n' https://127.0.0.1/admin/code/index.php

You should see active three times and 200. Only ports 22, 80 and 443 listen beyond loopback (MariaDB is on 127.0.0.1:3306, the others are the local DNS resolver):

ss -tlnH | awk '{print $4}' | sort -u
0.0.0.0:22
0.0.0.0:443
0.0.0.0:80
127.0.0.1:3306
127.0.0.53%lo:53
127.0.0.54:53
[::]:22
[::]:443
[::]:80

Step 6: Sign in to the administration area

Open https://<instance-address>/admin/code/ in a browser. The certificate is self-signed per instance, so accept the warning or install your own certificate (Step 9). Sign in as admin with the password from Step 4, then change it under users.

The TCExam administration sign-in page served over HTTPS

Step 7: Build questions and tests

TCExam organises content as modules, topics (subjects) and questions, all under the modules menu. The image ships a General Knowledge topic with three single-choice questions and a Sample Quiz that draws all three. Open tests to see how a test selects questions, sets its duration and score, and limits who can take it (user groups, IP ranges, dates):

The seeded Sample Quiz in the TCExam test editor

The modules menu also lists the question bank. You can add questions by hand, attach images and audio, or import whole topics from TCExam XML or TSV files (the import page under modules):

The TCExam question bank

Create candidate accounts under users (or import them from CSV/XML), put them in a group, and add that group to the test.

Step 8: Take a test as a candidate

Candidates sign in at https://<instance-address>/public/code/. They see the tests open to their groups, start one, answer the questions and, if the test allows it, see their results. The administrator account belongs to the default group, so it is offered the Sample Quiz:

The TCExam candidate area offering the Sample Quiz

Results, statistics and PDF reports are under tests (results) in the administration area; candidates see their own under results in the candidate area.

Step 9: Use your own hostname and certificate

Point a DNS A record at the instance (ideally an Elastic IP), then pin the name so TCExam's links and the certificate use it:

sudo tcexam-set-hostname exams.example.edu

This rewrites nginx's server_name, the certificate's subject alternative names and TCExam's K_PATH_HOST, and reloads nginx and PHP-FPM. To go back to the EC2 public name, run sudo tcexam-set-hostname --auto. To use a CA-issued certificate (for example from Let's Encrypt), install your key and certificate at /etc/ssl/tcexam/tcexam.key and /etc/ssl/tcexam/tcexam.crt, delete /etc/ssl/tcexam/tcexam.crt.cloudimg-san so the per-boot certificate manager leaves your certificate alone, then run sudo systemctl reload nginx.

Step 10: Enabling self-registration or password reset (opt-in)

Both are off by default. Password reset sends e-mail, so configure outbound mail first (Step 11). To enable them, edit the shared configuration and set the constant to true:

sudo grep -n "K_USRREG_ENABLED'" /var/www/tcexam/shared/config/tce_user_registration.php
sudo grep -n "K_PASSWORD_RESET'" /var/www/tcexam/shared/config/tce_config.php

For example, sudo sed -i "s/define('K_USRREG_ENABLED', false);/define('K_USRREG_ENABLED', true);/" /var/www/tcexam/shared/config/tce_user_registration.php, then sudo systemctl reload php8.3-fpm. Self-registration lets anyone on the internet create a candidate account, so enable it only behind your own access controls.

Step 11: Outbound e-mail

TCExam sends registration and password-reset mail with PHPMailer. Set your SMTP relay in /var/www/tcexam/shared/config/tce_email_config.php (host, port, user, password and sender address), then reload PHP-FPM. The image has no local mail server.

Step 12: Server components

Component Version Notes
TCExam 17.3.1 /var/www/tcexam, AGPL-3.0-or-later
nginx 1.24 (Ubuntu 24.04) TLS on 443, 80 redirects to HTTPS
PHP 8.3 (FPM) unix socket, not a TCP port
MariaDB 10.11 127.0.0.1 only, unix_socket authentication

Step 13: Filesystem layout

  • Application: /var/www/tcexam (root-owned and read-only to the web server, except cache/, admin/backup/ and the two log/ directories)
  • Configuration: /var/www/tcexam/shared/config/
  • Uploaded media: /var/www/tcexam/cache/
  • Credentials: /root/tcexam-credentials.txt
  • TLS key and certificate: /etc/ssl/tcexam/

Step 14: Managing the services

sudo systemctl restart mariadb php8.3-fpm nginx
systemctl is-active mariadb php8.3-fpm nginx

Step 15: Backups

Back up the database and the uploaded media. The database uses socket authentication, so run the dump as root on the instance and keep the files private:

sudo mariadb-dump --protocol=socket -uroot --single-transaction tcexam | sudo tee /root/tcexam-backup.sql > /dev/null
sudo tar czf /root/tcexam-cache.tgz -C /var/www/tcexam cache
sudo chmod 600 /root/tcexam-backup.sql /root/tcexam-cache.tgz

Copy both off the instance. To restore, create the database with CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci (the character set TCExam's schema uses), load the SQL into it and unpack cache/.

Step 16: Troubleshooting

  • Site not answering: check systemctl status tcexam-firstboot.service. If first boot failed, the web tier stays stopped by design.
  • Certificate warning: expected with the per-instance self-signed certificate; install your own (Step 9).
  • Logs: sudo journalctl -u nginx -u php8.3-fpm -u mariadb -u tcexam-firstboot and /var/www/tcexam/admin/log/.

Step 17: Security recommendations

  • Restrict SSH (port 22) to your own address.
  • Change the administrator password after first sign-in and keep /root/tcexam-credentials.txt private.
  • Keep self-registration off unless you need it (Step 10).
  • Install a CA-issued certificate and pin your hostname (Step 9).
  • OS security updates are applied automatically (unattended-upgrades); reboot for a new kernel.

Step 18: Support and licensing

TCExam is free software distributed under the GNU Affero General Public License v3.0 or later; the licence text ships at /var/www/tcexam/LICENSE. If you modify TCExam and offer it to users over a network, the AGPL requires you to offer them your modified source. cloudimg provides the image, its hardening and 24/7 support for the packaging. The TCExam name and logo are trademarks of Tecnick.com LTD; cloudimg is not affiliated with or endorsed by Tecnick.com LTD.