D2
Developer Tools AWS

Dolos 2.10.0 on AWS User Guide

| Product: Dolos 2.10.0 on Ubuntu 24.04 on AWS

Overview

This guide covers launching and using the Dolos 2.10.0 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.

Dolos is an open source tool from Team Dodona at Ghent University that detects source-code plagiarism. It parses each submission with tree-sitter, fingerprints it, and reports the most similar pairs of files with the matching fragments side by side. Teachers use it to find copied programming assignments; teams use it to find duplicated code. It understands JavaScript, TypeScript, Python, Java, C, C++, C#, Go, Rust, PHP, R, Scala, SQL and more.

The cloudimg image adds:

  • A private web UI, signed in on every page. Dolos's own server has no sign-in, so on this image it listens on 127.0.0.1:3000 only and nginx serves it on port 443. Every page, script and report file asks for a user name and password that first boot creates on your instance; only /healthz answers without it. Port 80 redirects to HTTPS. Sign-in attempts are rate-limited per client address.
  • Nothing shared between instances. The image ships no password, key or certificate. First boot creates the password (nginx keeps only a bcrypt hash of it) and a self-signed HTTPS certificate for your instance's addresses. Dolos and nginx do not start until first boot has finished.
  • Submissions never leave the server. sudo dolos-analyze runs each analysis as the unprivileged dolos account in a sandbox with no network access at all, and prints the bytes sent (0). A kernel rule also stops the dolos account from opening any network connection, and Dolos's --share upload option is switched off.
  • Metadata service blocked for Dolos, nginx, first boot and the helper commands; the AMI requires IMDSv2.
  • A pinned, compiled install. Dolos 2.10.0 and its 35 dependencies are installed from a lock file in which every package is pinned by its SHA-512 hash; the tree-sitter parsers are compiled on the image, not downloaded as binaries. Node.js 22 comes from NodeSource, whose signing key is pinned by fingerprint, and receives security updates through unattended upgrades with the rest of Ubuntu.
  • Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.

Trademark notice. Dolos is an open source project of Team Dodona at Ghent University, released under the MIT licence. "Dolos" is used here only to describe the software this image runs. cloudimg is not affiliated with, endorsed by, or sponsored by Team Dodona or Ghent University.

Prerequisites

  • An AWS account subscribed to the listing, an EC2 key pair and a VPC subnet. Dolos needs no internet access to analyse code; the instance needs it only for operating system updates.
  • A security group that allows TCP 443 (the web UI) and TCP 80 (redirects to HTTPS) from the networks that should reach them, and TCP 22 (SSH) from your own networks only. Dolos needs no other inbound port.

Step 1: Launch the instance

In the AWS Marketplace listing choose Continue to Subscribe, then Continue to Configuration, pick Dolos 2.10.0 on Ubuntu 24.04 as the software version and your Region, then Launch through EC2. Choose t3.medium or larger (m5.large suits a whole course's submissions), your key pair and a security group as above.

Step 2: Connect to your instance

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

Step 3: Check the services

First boot takes a few seconds. Then Dolos, its network guard, nginx and the first boot unit are active, Dolos listens on loopback only and nginx on 80 and 443:

systemctl is-active dolos dolos-egress-guard nginx dolos-firstboot
sudo ss -tlnp | awk 'NR==1 || /nginx|sshd|node/' | awk '{print $1, $4, $6}' | sed -E 's/,pid=[0-9]+,fd=[0-9]+//g'
active
active
active
active
State Local Peer
LISTEN 127.0.0.1:3000 users:(("node"))
LISTEN 0.0.0.0:443 users:(("nginx"),("nginx"),("nginx"))
LISTEN 0.0.0.0:80 users:(("nginx"),("nginx"),("nginx"))
LISTEN 0.0.0.0:22 users:(("sshd"),("systemd"))
LISTEN [::]:443 users:(("nginx"),("nginx"),("nginx"))
LISTEN [::]:80 users:(("nginx"),("nginx"),("nginx"))
LISTEN [::]:22 users:(("sshd"),("systemd"))

Step 4: The release

dolos -v
ls /usr/share/doc/dolos-cloudimg/ /usr/share/doc/dolos-cloudimg/sample-dataset/
Dolos v2.10.0
Node v22.23.4
Tree-sitter ^0.25.1
/usr/share/doc/dolos-cloudimg/:
LICENSE
sample-dataset
third-party-packages.txt

/usr/share/doc/dolos-cloudimg/sample-dataset/:
alice_bubble_sort.js
bob_bubble_sort.js
carol_quick_sort.js
dave_bubble_sort.js

The web UI starts out showing the report of this small sample: four JavaScript files, two of which are the same bubble sort with renamed variables.

Step 5: Get your sign-in details

The credentials file holds the address the web UI is served on and the sign-in, generated on this instance:

sudo cat /root/dolos-credentials.txt
DOLOS_URL=https://<public-ip>/
#
DOLOS_USER=admin
DOLOS_PASSWORD=<DOLOS_PASSWORD>

The password is 32 letters and digits from the kernel's random number generator, created on first boot and known to nobody else. nginx stores only a bcrypt hash of it in /etc/nginx/dolos.htpasswd. To replace it, run sudo dolos-rotate-password: the old password stops working at once and the new one is written to the same file.

Step 6: Check the certificate

The HTTPS certificate is self-signed and was generated on your instance. Note its fingerprint here, over SSH, and compare it with what your browser shows before you accept it:

openssl x509 -in /etc/nginx/ssl/dolos.crt -noout -subject -enddate -fingerprint -sha256 -ext subjectAltName | sed -E 's/[0-9]+(\.[0-9]+){3}/<ip>/g; s/ec2-[0-9-]+/ec2-<ip>/g; s/ip-[0-9-]+/ip-<ip>/g; s/=([0-9A-F]{2}:){31}[0-9A-F]{2}/=<64 hex digits>/'
subject=CN = <ip>, O = cloudimg
notAfter=Feb  9 21:28:30 2029 GMT
sha256 Fingerprint=<64 hex digits>
X509v3 Subject Alternative Name: 
    IP Address:<ip>, IP Address:<ip>, DNS:ec2-<ip>.compute-1.amazonaws.com, DNS:ip-<ip>.ec2.internal, IP Address:<ip>, DNS:localhost

(The sed only hides this example's addresses; run the openssl command on its own to see yours.) It names the instance's public and private addresses and DNS names, and 127.0.0.1.

Step 7: Open the web UI

Open https://<public-ip>/ in your browser, accept the certificate once you have checked its fingerprint, and sign in as admin with the password from Step 5. The overview shows the current report: how many files were analysed, the highest and average similarity, and how the similarities are distributed:

The Dolos overview of the sample report

View by pair ranks every pair of files by similarity, with the longest shared fragment and the total overlap:

The ranked list of file pairs

Open a pair to compare the two files. Matching fragments are highlighted; for very similar files Dolos opens the diff view, which shows that bob_bubble_sort.js is alice_bubble_sort.js with its variables renamed:

Comparing two files side by side

View by submission lists every file with its highest similarity to any other; View by cluster and View by graph group files that are similar to each other:

Every submission with its highest similarity

The web UI reads the report files only; it cannot upload, change or delete anything. Its pages load nothing from outside the instance (the links to Dolos's documentation and GitHub are ordinary links).

Step 8: Analyse your own submissions

Copy the files to the instance (with scp, for example) and run sudo dolos-analyze on them. It accepts a directory of files, a single .zip archive, or two or more files. This example analyses a copy of the sample:

mkdir -p ~/dolos-demo && cp /usr/share/doc/dolos-cloudimg/sample-dataset/*.js ~/dolos-demo/
sudo dolos-analyze --id demo --name "Demo" -l javascript ~/dolos-demo 2>&1
Analysing 4 input(s) as report demo (as the dolos account, no network) ...
Running as unit: run-u221.service; invocation ID: 97af2696172245dcab6ce8bce0ad9713
Writing results to directory: /var/lib/dolos/reports/demo/out
Metadata written.
Pairs written.
Kgrams written.
Files written.
Completed
Finished with result: success
Main processes terminated with: code=exited/status=0
Service runtime: 401ms
CPU time consumed: 491ms
Memory peak: 1.5M
Memory swap peak: 0B
IP traffic received: 0B
IP traffic sent: 0B
Report demo is ready and shown in the web UI: https://<public-ip>/

Reload the web UI to see the new report. dolos-analyze copies your files into /var/lib/dolos/inputs/<id>, runs Dolos as the dolos account with no network access (the last two lines of the summary are the bytes it received and sent), writes the report to /var/lib/dolos/reports/<id>/out and switches the web UI to it. Without --id, the report is named after the date and --name.

  • Language. Dolos guesses the language from the file extensions; set it with -l (python, java, c, cpp, csharp, javascript, typescript, go, rust, php, r, scala, sql, bash, elm, groovy, ocaml, verilog, ...).
  • Labels and names. To label submissions (for example by class group) and keep each student's name with their file, put an info.csv with the columns filename,full_name,labels,created_at at the top of the directory; dolos-analyze then analyses it as a Dolos CSV dataset.
  • Ignoring the starter code. -i template.js leaves out code that every student received.
  • Tuning. -k, -w, -m, -M, -s, -S, -L and --sort-by work as in dolos run --help.

List the reports, switch the web UI between them, and remove the ones you no longer need:

sudo dolos-analyze --list
sudo dolos-analyze --use sample
sudo dolos-analyze --remove demo
rm -rf ~/dolos-demo
demo * (shown in the web UI)
sample 
The web UI now shows report sample.
Removed report demo.

Step 9: Use the command line

The dolos command works as upstream documents it, for quick checks in the terminal:

cd /usr/share/doc/dolos-cloudimg/sample-dataset && dolos run -f terminal -l javascript alice_bubble_sort.js bob_bubble_sort.js carol_quick_sort.js
 File path          File path          Similarity  Longest        Total overlap
                                                   fragment

 alice_bubble_sort  bob_bubble_sort.j  1           41             82
 .js                s
 alice_bubble_sort  carol_quick_sort.  0.027397    1              2
 .js                js
 bob_bubble_sort.j  carol_quick_sort.  0.027397    1              2
 s                  js

Upstream Dolos can upload a report to the public dolos.ugent.be service with --share. On this image that option is refused, by the dolos command and by dolos-analyze, so a report is never sent anywhere by mistake:

dolos run --share /usr/share/doc/dolos-cloudimg/sample-dataset/*.js; echo "exit $?"
dolos: --share is not available on this image: analyses and reports never leave this server (see sudo dolos-analyze)
exit 2

Step 10: Your own DNS name and certificate

Point a DNS name at the instance (an Elastic IP keeps the address across stops), then run:

sudo dolos-set-hostname dolos.your-domain.example

It sets nginx's server name and the HTTP redirect to the new name, generates a new certificate that names it, updates DOLOS_URL in the credentials file and reloads nginx. The password does not change. To use a certificate from your own CA instead, run the command first, then replace /etc/nginx/ssl/dolos.crt (the full chain) and /etc/nginx/ssl/dolos.key (mode 0600, owned by root) and reload nginx with sudo nginx -t && sudo systemctl reload nginx.

Step 11: Security checks

Every page and report file refuses a visitor without the password, and sudo dolos-selftest signs in end to end with the password from the credentials file:

for p in / /data/pairs.csv /api/reports; do curl -s -o /dev/null -w "anonymous $p: %{http_code}\n" --cacert /etc/nginx/ssl/dolos.crt https://127.0.0.1$p; done
curl -s -o /dev/null -w 'port 80: %{http_code}\n' http://127.0.0.1/
sudo dolos-selftest
anonymous /: 401
anonymous /data/pairs.csv: 401
anonymous /api/reports: 401
port 80: 301
DOLOS_SELFTEST_OK (anonymous + wrong password 401 on 6 routes; the login reads the UI and the 4 report files; 6 pair(s); Dolos as dolos; egress guard active)

Dolos runs as the dolos account and exchanges packets with loopback only; nginx and first boot cannot reach the instance metadata service; the dolos account cannot open any network connection (the counter shows the connection attempts that were refused); and root cannot log in over SSH:

systemctl show -p User -p IPAddressAllow -p IPAddressDeny dolos.service
systemctl show -p IPAddressDeny nginx.service dolos-firstboot.service
sudo nft list table inet cloudimg_dolos
sudo sshd -T | grep -E '^(permitrootlogin|passwordauthentication) '
IPAddressAllow=127.0.0.0/8 ::1/128
IPAddressDeny=::/0 0.0.0.0/0
User=dolos
IPAddressDeny=168.63.129.16/32 169.254.169.254/32 fd00:ec2::254/128

IPAddressDeny=168.63.129.16/32 169.254.169.254/32 fd00:ec2::254/128
table inet cloudimg_dolos {
    chain output {
        type filter hook output priority filter; policy accept;
        meta skuid 997 ct state new counter packets 0 bytes 0 reject
    }
}
permitrootlogin no
passwordauthentication no

Who can see the reports. Anyone with the web UI password sees every file of the report it shows, so share the password only with the people who may read the submissions, and rotate it (sudo dolos-rotate-password) when someone should lose access. Submissions and reports are stored under /var/lib/dolos, readable by root and the dolos account only.

Step 12: Where things are

What Where
Reports (one directory per analysis) /var/lib/dolos/reports/<id>/out
Copies of the analysed files /var/lib/dolos/inputs/<id>
The report the web UI shows /var/lib/dolos/current (switch with sudo dolos-analyze --use <id>)
The sign-in /root/dolos-credentials.txt (root only); hash in /etc/nginx/dolos.htpasswd
HTTPS certificate and key /etc/nginx/ssl/
Dolos and its packages /opt/dolos/app
Licences /usr/share/doc/dolos-cloudimg/
Helper commands /usr/local/sbin/dolos-analyze, dolos-rotate-password, dolos-set-hostname, dolos-selftest

Logs are in the journal: sudo journalctl -u dolos -u nginx. The nginx access log records requests without query strings or credentials.

Step 13: Backups and upgrades

Reports and the analysed files are the only data; back up /var/lib/dolos if you want to keep them:

sudo tar -C /var/lib -czf dolos-$(date +%F).tar.gz dolos

Ubuntu, nginx and Node.js 22 (from NodeSource) receive security updates through unattended upgrades. Dolos itself is not upgraded automatically; it is pinned to 2.10.0 with its dependencies, and a new cloudimg version of this image brings a newer release. The image runs Node.js only: npm, npx and corepack are not installed.

Step 14: Security recommendations

  • Keep TCP 443 and 80 open only to the networks of the people who review the reports: they contain your students' or colleagues' code.
  • Replace the self-signed certificate with your own (Step 10) before you share the address widely.
  • Rotate the password when the group of reviewers changes, and remove reports you no longer need with sudo dolos-analyze --remove <id>.
  • Analyse submissions with sudo dolos-analyze, which keeps them off the network, rather than running dolos on them as another account.
  • Keep the instance patched.

Support and licensing

cloudimg provides 24/7 technical support for this image by email and live chat: support@cloudimg.co.uk or https://www.cloudimg.co.uk/support. Include the instance type, the Region and the output of Steps 3 and 11.

Dolos is released under the MIT licence; its licence is at /usr/share/doc/dolos-cloudimg/LICENSE, and third-party-packages.txt lists every bundled package with its licence (the bundled Modelica grammar, tree-sitter-modelica, is under the OSMC Public License and ships unmodified with its source). Node.js, nginx and the Ubuntu packages are under their own licences (see /usr/share/doc/<package>/copyright). cloudimg is not affiliated with, endorsed by, or sponsored by Team Dodona or Ghent University.