Razzia 4.0.1 on AWS User Guide
Overview
This guide covers launching and using Razzia 4.0.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.
Razzia is an open source, self-hosted live multiplayer quiz game. A host builds quizzes and runs a game from the manager screen; players open the site on their phones, type the game PIN the host shows, pick a name and answer in real time, with a leaderboard after each question. Players need no account. It suits classrooms, training sessions, workshops and events.
Razzia is free software published under the MIT License; the licence ships in the image at /usr/share/doc/razzia/. cloudimg is not affiliated with, endorsed by, or sponsored by the Razzia project or its contributors. This image packages the upstream open source release together with cloudimg's provisioning, hardening and support.
What is included:
- Razzia 4.0.1 from the project's official container image (
ghcr.io/ralex91/razzia:4.0.1, pinned by digest), with the Alpine Linux security updates of the build date applied and the image flattened into one layer, shipped ascloudimg/razzia:4.0.1. The application code is byte-identical to upstream - Docker Engine (Docker CE) from Docker's official repository, running the Razzia container read-only on
127.0.0.1:3000 - nginx serving Razzia over HTTPS at
https://<instance-address>/; port 80 only ever redirects to HTTPS - A per-instance manager password, session signing key and HTTPS certificate, all generated on first boot. No default, shared or published password ships in the image, and the web server does not start until first boot has proven the password works
- A ready-made "Example Quizz" so you can run a game straight away
- 24/7 cloudimg support

Security posture
- No default login. Razzia 4 reads the manager password from its environment and refuses every manager sign-in while none is set. First boot generates this instance's own manager password and session signing key into
/etc/razzia/secrets/razzia.env(readable by root only). The container only starts when that file exists and passes a start-time check (no empty, short or well-known value), and the values are never placed in the container's configuration or on a command line. - Fixed 4.0.1 crash. Razzia 4.0.1 validates every message a game client sends. Earlier releases (3.x) could be crashed by anyone who could open the game page, by sending a malformed message; this image ships the fixed release, and the build proved that the same malformed message is rejected while the server keeps serving.
- Updated, locked-down container. The official 4.0.1 image carried Alpine packages with published advisories (nginx, Node.js and Brotli). This image applies the Alpine security updates and flattens the image so no older package copy remains; a vulnerability scan of the shipped image reports no high or critical finding. The container runs with a read-only root filesystem, a minimal capability set,
no-new-privileges, no core dumps, memory and process limits, and is published on the loopback interface only. - Only the web tier faces the network. The listening set is exactly 22, 80 and 443. Razzia itself (3000) listens on
127.0.0.1only. - The site address comes from configuration, never from the request. On first boot and every later boot
razzia-set-hostnamesets nginx's allowed name and the certificate from/etc/cloudimg/razzia-hostnameif you set one, otherwise from IMDSv2 (public DNS name, else public IPv4, else private IPv4). nginx closes the connection for any otherHost, and the lobby shows players this fixed address. - Real client addresses and a cross-site guard. nginx overwrites
X-Forwarded-Forwith the real peer address. A state-changing request or WebSocket upgrade whoseOriginis not this instance is refused with403. Razzia's sessions are tokens sent in a request header (not cookies), and none of itsGETroutes changes state or fetches a URL. - Manager sign-in is rate limited. nginx allows 10 manager sign-in attempts a minute per address (burst 5) and answers
429beyond that. - Uploads are contained. Media uploads (up to 100 MiB each) need the manager's session; every other request body is limited to 1 MiB. Razzia types uploads by their content (images, audio and video only), and nginx serves uploaded files with
nosniffand a sandbox Content-Security-Policy so a file can never run as a page. - No instance metadata access for the application. The Razzia container is blocked from the instance metadata endpoints by a firewall rule in Docker's
DOCKER-USERchain, and the nginx, Docker and Razzia units by systemdIPAddressDeny(169.254.169.254, the IPv6 and IPv4-mapped forms, and the Azure wire-server). Razzia's server never fetches a URL itself. Only the first-boot and address units read metadata, once, for the site address. - IMDSv2 required. The AMI is registered with
ImdsSupport v2.0, so instances refuse token-less metadata requests. - Key-only SSH. Password and keyboard-interactive logins, root login and X11 forwarding are off in
/etc/ssh/sshd_config.d/00-cloudimg.conf; you sign in asubuntuwith your EC2 key pair. - Patched at build time. The image is a full
apt full-upgrade; unattended upgrades stay on for Ubuntu and for Docker's repository.
Prerequisites
- An AWS account where you can subscribe to AWS Marketplace products and launch EC2 instances
- An EC2 key pair in the target Region
- A VPC and subnet, with a public IP address on the instance if your players reach it over the internet
- A security group that allows
22/tcpfrom your management network, and80/tcpand443/tcpfrom your players' networks. No other port is needed; do not open 3000
Recommended instance type: m5.large (2 vCPU, 8 GiB RAM). Razzia is light: a t3.medium is enough for evaluation and small classes, and m5.large gives headroom for large live games and media-heavy quizzes.
Step 1: Launch from AWS Marketplace
- Open the Hardened Moodle & E-Learning Platforms AMIs listing by cloudimg, choose View purchase options, and subscribe.
- Choose Continue to Configuration. Under Software version choose
Razzia 4.0.1 on Ubuntu 24.04, pick your Region, and choose Continue to Launch. - Under Choose Action select Launch through EC2.
- Set the instance type to m5.large, choose your key pair, and use the seller's security group settings (ports 22, 80 and 443), narrowing port 22 to your management network.
- Launch. First boot finishes within about a minute.
Step 2: Launch from the AWS CLI
Workstation commands. Replace <ami-id> with the AMI ID shown for the Razzia 4.0.1 on Ubuntu 24.04 software version on the listing's launch page, and use your own VPC, subnet, key pair and address ranges.
aws ec2 create-security-group --group-name razzia-sg \
--description "Razzia" --vpc-id <vpc-id>
aws ec2 authorize-security-group-ingress --group-id <security-group-id> \
--protocol tcp --port 22 --cidr <your-ip>/32
aws ec2 authorize-security-group-ingress --group-id <security-group-id> \
--protocol tcp --port 80 --cidr <players-cidr>
aws ec2 authorize-security-group-ingress --group-id <security-group-id> \
--protocol tcp --port 443 --cidr <players-cidr>
aws ec2 run-instances --image-id <ami-id> --instance-type m5.large \
--key-name <key-name> --subnet-id <subnet-id> \
--security-group-ids <security-group-id> --associate-public-ip-address \
--metadata-options HttpTokens=required \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=razzia}]'
aws ec2 describe-instances --instance-ids <instance-id> \
--query "Reservations[].Instances[].[PublicDnsName,PublicIpAddress]" --output text
Step 3: Connect over SSH
ssh -i <key.pem> ubuntu@<public-dns>
The login user is ubuntu.
Step 4: Confirm Razzia is running
First boot generates this instance's secrets and certificate, starts the Razzia container, proves the manager password works and only then starts the web server. When the three units are active, the game is ready:
systemctl is-active docker razzia nginx
active
active
active
Confirm Razzia answers over HTTPS on the instance itself. The certificate is self-signed per instance, so -k is expected until you install your own (Step 10):
curl -sk https://127.0.0.1/api/health; echo
{"status":"ok"}
The container and the image it runs:
sudo docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}"
NAMES IMAGE STATUS PORTS
razzia cloudimg/razzia:4.0.1 Up 20 seconds 127.0.0.1:3000->3000/tcp
The updated packages inside the container:
sudo docker exec razzia sh -c 'apk info -v 2>/dev/null | grep -E "^(nginx|nodejs|brotli-libs)-[0-9]"'
brotli-libs-1.2.1-r0
nginx-1.30.6-r0
nodejs-24.22.1-r0
Step 5: Check what the network can reach
sudo ss -Htln | awk '{print $4}' | sort -u
0.0.0.0:22
0.0.0.0:443
0.0.0.0:80
127.0.0.1:3000
127.0.0.53%lo:53
127.0.0.54:53
[::]:22
[::]:443
[::]:80
Only SSH, HTTP (redirect) and HTTPS listen on the network; Razzia is on loopback. The container cannot reach the instance metadata service:
sudo docker exec razzia wget -q -T 5 -O - http://169.254.169.254/latest/meta-data/ || true
wget: download timed out
Step 6: Retrieve the manager password
sudo cat /root/razzia-credentials.txt
# Razzia 4.0.1 - generated on this instance's first boot by razzia-postboot.service
# This password is unique to this instance. Keep this file secret (0600 root).
#
# Players join at RAZZIA_URL with the game PIN the host shows (no account needed).
# The host signs in at RAZZIA_URL/manager with MANAGER_PASSWORD (self-signed certificate made on first boot).
RAZZIA_URL=https://ec2-203-0-113-10.compute-1.amazonaws.com/
MANAGER_PASSWORD=<the 24-character password generated for this instance>
#
# Change the password: edit /etc/razzia/secrets/razzia.env, then sudo systemctl restart razzia
# Change the served name + certificate: sudo razzia-set-hostname <your-dns-name>
# Quizzes, media and results live in /var/lib/razzia/config (back this directory up).
Keep this password private: it controls every quiz and game on the instance.
Step 7: Sign in as the host
Open https://<public-dns>/manager in your browser. Your browser warns about the self-signed certificate until you install your own (Step 10); accept it for this address. Enter the manager password from Step 6. A wrong password is refused with "Invalid password".

After signing in you see your quizzes. From here you can Play a quiz, edit or create quizzes under Quizz, and review finished games under Results.

Step 8: Run a live game
- Select Example Quizz (or your own quiz) and choose Start game. The lobby shows the address players should open, a QR code and the six-digit Game PIN.
- Players open
https://<public-dns>/on a phone or laptop, type the PIN, choose Submit, then enter a name. They appear in your lobby as they join. - Choose Start when everyone is in. Each question shows on your screen and the answer buttons on the players' devices; a leaderboard follows each question and a podium ends the game.


The lock button in the lobby stops new players joining once your group is complete.
Step 9: Prove the whole game path from the command line
razzia-roundtrip.sh exercises the real public path on the instance: HTTPS with this instance's certificate, the manager sign-in (and the refusal of wrong passwords), the API's access rules, then a game is created, a test player joins over the game's live connection and the host's connection sees the player arrive. It also sends the malformed message fixed in 4.0.1 and checks the server keeps serving. Everything it creates lives in memory only; nothing is written to your quizzes or results.
sudo razzia-roundtrip.sh
OK round-trip https://ec2-203-0-113-10.compute-1.amazonaws.com/: health, web app, manager auth (per-VM ok; wrong, PASSWORD, empty refused), API gates, game created, player joined over socket.io, host saw the player, malformed payload rejected and the server kept serving
Step 10: Use your own hostname and certificate
Point a DNS name at the instance (an Elastic IP keeps the address across stop/start), then set it as the served name. This regenerates the self-signed certificate for the name, updates nginx's allowed name and the cross-site guard, and updates RAZZIA_URL in the credentials file:
sudo razzia-set-hostname quiz.example.com
To use a certificate from your own certificate authority, replace the pair nginx reads and reload it:
sudo install -m 0644 your-cert-chain.pem /etc/ssl/razzia/razzia.crt
sudo install -m 0600 your-key.pem /etc/ssl/razzia/razzia.key
sudo nginx -t && sudo systemctl reload nginx
A name set with razzia-set-hostname is pinned in /etc/cloudimg/razzia-hostname. Without one, the instance follows its public DNS name across stop and start.
Step 11: Change the manager password
Edit MANAGER_PASSWORD in /etc/razzia/secrets/razzia.env (letters and digits, at least 16 characters), update the credentials file to match, and restart Razzia. Host sessions already signed in stay valid until they expire (12 hours); to end them at once, also replace JWT_SECRET with a new value of at least 32 letters and digits (for example the output of openssl rand -hex 32):
sudo nano /etc/razzia/secrets/razzia.env
sudo nano /root/razzia-credentials.txt
sudo systemctl restart razzia
The start-time check refuses an empty, short or well-known password, and Razzia then stays stopped until it is fixed (journalctl -u razzia shows why). Keep the file at mode 0600, owner root.
Step 12: Quizzes, media and disk space
Quizzes, uploaded media and game results are stored under /var/lib/razzia/config on the instance's root volume. Each media upload can be up to 100 MiB, so a busy media library grows quickly; check the space in use and grow the EBS volume when you need to:
sudo du -sh /var/lib/razzia/config; df -h / | tail -1
Step 13: Back up and restore
Back up the whole configuration directory (quizzes, media, results):
sudo tar -C /var/lib/razzia -czf /root/razzia-config-backup.tar.gz config && sudo ls -l /root/razzia-config-backup.tar.gz
Copy the archive off the instance (for example to Amazon S3). To restore on this or a new cloudimg Razzia instance:
sudo systemctl stop razzia
sudo tar -C /var/lib/razzia -xzf razzia-config-backup.tar.gz
sudo systemctl start razzia
The manager password and session key are per instance and are not part of the backup.
Step 14: Updates
Ubuntu security updates and Docker Engine updates install automatically (unattended upgrades). The Razzia container image is fixed at build time and never pulled on boot; new Razzia releases arrive as new software versions of this listing, which you launch and restore a backup into (Step 13).
Support
cloudimg provides 24/7 support for this image. Contact support@cloudimg.co.uk with your instance details. For Razzia itself, see the project at github.com/Ralex91/Razzia.