Deployment guide

Razzia 4.0.1

Overview

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, which suits classrooms, training sessions, workshops and events.

This guide covers launching and using Razzia 4.0.1 on Ubuntu 24.04 from SecureAnyCloud on Amazon EC2. The image is one version of the SecureAnyCloud Hardened Moodle & E-Learning Platforms AMIs listing on AWS Marketplace. Select 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 free software published under the MIT License, and the license ships in the image at /usr/share/doc/razzia/. This image packages the upstream open source release together with SecureAnyCloud's provisioning, hardening and support. SecureAnyCloud is not affiliated with, endorsed by, or sponsored by the Razzia project or its contributors.

What you get:

  • Razzia 4.0.1 from the project's official container image (ghcr.io/ralex91/razzia:4.0.1, pinned by digest), shipped as sac/razzia:4.0.1. The Alpine Linux security updates of the build date are applied and the image is flattened into one layer. 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>/, with port 80 used only to redirect 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 that the password works
  • A ready-made "Example Quizz" so you can run a game straight away
  • 24/7 SecureAnyCloud 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 starts only when that file exists and passes a start-time check that rejects empty, short and well-known values. 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. In earlier 3.x releases, anyone who could open the game page could crash the server by sending a malformed message. This image ships the fixed release, and the build confirmed 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, and memory and process limits. It 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.1 only.
  • The site address comes from configuration, never from the request. On first boot and every later boot, razzia-set-hostname sets nginx's allowed name and the certificate. It uses /etc/sac/razzia-hostname if you set one, and otherwise IMDSv2 (public DNS name, else public IPv4, else private IPv4). nginx closes the connection for any other Host, and the lobby shows players this fixed address.
  • Real client addresses and a cross-site guard. nginx overwrites X-Forwarded-For with the real peer address. A state-changing request or WebSocket upgrade whose Origin is not this instance is refused with 403. Razzia's sessions are tokens sent in a request header, not cookies, and none of its GET routes 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 429 beyond that.
  • Uploads are contained. Media uploads (up to 100 MiB each) need the manager's session, and every other request body is limited to 1 MiB. Razzia types uploads by their content (images, audio and video only). nginx serves uploaded files with nosniff and a sandbox Content-Security-Policy, so a file can never run as a page.
  • No instance metadata access for the application. A firewall rule in Docker's DOCKER-USER chain blocks the Razzia container from the instance metadata endpoints. The nginx, Docker and Razzia units are blocked by systemd IPAddressDeny (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-sac.conf. You sign in as ubuntu with your EC2 key pair.
  • Patched at build time. The image is built from a full apt full-upgrade, and 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/tcp from your management network, and 80/tcp and 443/tcp from your players' networks. No other port is needed, so 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.

1

Launch from AWS Marketplace

  • Open the Hardened Moodle & E-Learning Platforms AMIs listing by SecureAnyCloud, 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 and choose your key pair. Use the seller's security group settings (ports 22, 80 and 443), and narrow port 22 to your management network.
  • Launch the instance. First boot finishes within about a minute.
2

Launch from the AWS CLI

Run these commands from your workstation. 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. 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
3

Connect over SSH

ssh -i <key.pem> ubuntu@<public-dns>

The login user is ubuntu.

4

Confirm Razzia is running

First boot generates this instance's secrets and certificate and starts the Razzia container. It proves that 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 that 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"}

List the container and the image it runs.

sudo docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}"
NAMES IMAGE STATUS PORTS razzia sac/razzia:4.0.1 Up 20 seconds 127.0.0.1:3000->3000/tcp

Check 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
5

Check what the network can reach

List the listening sockets on the instance.

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. Then confirm that 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
6

Retrieve the manager password

Read the credentials file with sudo.

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.

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 the warning for this address.

Enter the manager password from Step 6. A wrong password is refused with "Invalid password".

After you sign in, your quizzes are listed. You can Play a quiz, edit or create quizzes under Quizz, and review finished games under Results.

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.
  • Have 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 appear on the players' devices. A leaderboard follows each question, and a podium ends the game.

Use the lock button in the lobby to stop new players joining once your group is complete.

9

Prove the whole game path from the command line

Run razzia-roundtrip.sh to exercise the real public path on the instance. It checks HTTPS with this instance's certificate, the manager sign-in (including the refusal of wrong passwords) and the API's access rules. It then creates a game, joins a test player over the game's live connection, and confirms that the host's connection sees the player arrive.

The script also sends the malformed message fixed in 4.0.1 and checks that the server keeps serving. Everything it creates lives in memory only, and 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
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 the name 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 that nginx reads and reload nginx.

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/sac/razzia-hostname. If you set no name, the instance follows its public DNS name across stop and start.

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 that are 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. Razzia then stays stopped until you fix it, and journalctl -u razzia shows why. Keep the file at mode 0600, owned by root.

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
13

Back up and restore

Back up the whole configuration directory, which holds quizzes, media and 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 SecureAnyCloud Razzia instance, run:

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.

14

Updates

Ubuntu security updates and Docker Engine updates install automatically through 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. Launch the new version and restore a backup into it (Step 13).

Support

SecureAnyCloud provides 24/7 support for this image. Contact sales@secureanycloud.com with your instance details. For Razzia itself, see the upstream project at github.com/Ralex91/Razzia.

Deploy on AWS

Launch Razzia 4.0.1 on Ubuntu 24.04 on AWS with 24/7 support from SecureAnyCloud.

View on Marketplace

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on AWS