Skip to content

Installatiehandleiding

Deze handleiding beschrijft het uitrollen van Safe Exam Support (SES) op een single productieserver, geschikt voor kleine tot middelgrote implementaties.

High Availability Architectuur

Voor grotere implementaties die zero-downtime failover en automatische database-herstel vereisen, biedt SES ook een multi-VM HA-architectuur met Patroni auto-failover, Docker Swarm en pgBouncer connection pooling. Deze setup overleeft individuele VM-fouten en handelt examen-start verbindingspieken probleemloos af. Neem contact op met het projectteam voor meer informatie over HA-uitrol.


Vereisten

Serververeisten

Bron Minimum Aanbevolen
CPU 4 vCPU 8 vCPU
RAM 8 GB 16 GB
Opslag 50 GB SSD 150 GB SSD
OS Ubuntu 22.04 LTS Ubuntu 24.04 LTS

Netwerkvereisten

  • Openbaar IP-adres met poorten 80 en 443 open
  • Domeinnaam wijzend naar het server-IP
  • Uitgaande HTTPS (443) voor Let's Encrypt-validatie

Softwarevereisten

  • Docker 24.0+
  • Docker Compose 2.20+
  • Make (optioneel, voor gemakscommando's)

Architectuuroverzicht

Single-server architectuur Figuur 1: Single-server implementatie-architectuur

Container-stack

Service Image Doel
load-balancer nginx:1.27-alpine TLS-terminatie, routing
ses-proxy (3x) Custom Smart proxy met Lua-validatie
ses-server (3x) Custom Django-backend
postgres postgres:16-alpine Primaire database
pgbouncer Custom Verbindingspooler
redis redis:7-alpine Sessie-cache, rate limiting

High Availability Architectuur

Voor grotere implementaties biedt SES een multi-VM HA-architectuur met automatische failover:

HA architectuur Figuur 2: Multi-VM HA-architectuur met Patroni auto-failover

Kenmerk Single Server HA
VM's 1 3
Containers 9 20
Database Enkele PostgreSQL Patroni-cluster (1 leader + 2 replica's)
Failover Handmatig herstart Automatisch (~10-30s)
Verbindingspooling pgBouncer pgBouncer
Load balancer Enkele nginx 3 replica's (Swarm VIP)
Overleeft Proces-crash 1 VM-fout

Neem contact op met het projectteam

HA-uitrol vereist aanvullende infrastructuurplanning (Docker Swarm-setup, netwerkconfiguratie, back-upstrategie). Neem contact op met het projectteam voor begeleiding bij HA-uitrol.


Stap 1: Server Voorbereiden

1.1 Systeem Updaten

apt update && apt upgrade -y

1.2 Docker Installeren

curl -fsSL https://get.docker.com | sh
usermod -aG docker $USER

1.3 Make Installeren (Optioneel)

apt install -y make

1.4 OS-limieten Configureren

Maak systemd-override voor Docker:

mkdir -p /etc/systemd/system/docker.service.d
cat > /etc/systemd/system/docker.service.d/ulimit.conf << 'EOF'
[Service]
LimitNOFILE=65535:65535
EOF
systemctl daemon-reload
systemctl restart docker

1.5 Kernelparameters Tunen

cat >> /etc/sysctl.conf << 'EOF'
# SES hoge-concurrentie tuning
net.core.somaxconn=65535
net.ipv4.tcp_max_syn_backlog=65535
net.ipv4.ip_local_port_range=1024 65535
net.ipv4.tcp_max_tw_buckets=200000
net.ipv4.tcp_fin_timeout=15
EOF
sysctl -p

Stap 2: Repository Clonen

cd /srv
git clone https://github.com/xxx/ses.git
cd ses

Stap 3: Omgeving Configureren

3.1 Omgevingsbestand Aanmaken

cp .env.example .env.prd

3.2 Configuratie Bewerken

nano .env.prd

Verplichte Variabelen

Variabele Beschrijving Voorbeeld
SECRET_KEY Django secret key (50+ willekeurige tekens) openssl rand -hex 32
DB_PASSWORD PostgreSQL-wachtwoord openssl rand -hex 32
REDIS_PASSWORD Redis-wachtwoord openssl rand -hex 32
SES_SESSION_TOKEN_SECRET HMAC-ondertekeningssleutel openssl rand -hex 32
DJANGO_ALLOWED_HOSTS Toegestane hostnamen .example.com
CSRF_TRUSTED_ORIGINS Vertrouwde origins https://*.example.com

Optionele Variabelen

Variabele Standaard Beschrijving
GUNICORN_WORKERS 16 Worker-processen
GUNICORN_THREADS 64 Threads per worker
RATE_LIMIT_GLOBAL 500000 Globale rate limit
RATE_LIMIT_INSTITUTE 500000 Rate limit per instituut

Stap 4: SSL-certificaten

Kies één van de twee opties hieronder.

Optie A: Instituutcertificaat

Als uw instituut een TLS-certificaat biedt (bijv. van DigiCert, QuoVadis, of een interne CA):

4.A.1 Certificaatbestanden Kopiëren

cp your-institute-fullchain.pem services/load-balancer/certs/cert.pem
cp your-institute-privkey.pem services/load-balancer/certs/key.pem

4.A.2 Verifiëren

openssl x509 -in services/load-balancer/certs/cert.pem -noout -text | grep -i subject

Het certificaat moet alle subdomeinen uit Stap 7 (DNS-configuratie) dedekken. Wanneer het certificaat wordt vernieuwd door uw instituut, herhaal 4.A.1 en rol uit opnieuw uit

make prod-deploy

Optie B: Let's Encrypt (Gratis, Auto-vernieuwend)

4.B.1 Certbot Installeren

apt install -y certbot

4.B.2 Certificaat Verkrijgen

certbot certonly --standalone -d example.com \
    -d www.example.com \
    -d ems1.example.com \
    -d ems2.example.com \
    -d admin.example.com \
    -d manuals.example.com

4.B.3 Certificaten Kopiëren

cp /etc/letsencrypt/live/example.com/fullchain.pem \
    services/load-balancer/certs/cert.pem
cp /etc/letsencrypt/live/example.com/privkey.pem \
    services/load-balancer/certs/key.pem

4.B.4 Auto-vernieuwing

crontab -e

Voeg toe:

0 3 * * * certbot renew --quiet --post-hook "cp /etc/letsencrypt/live/example.com/fullchain.pem /srv/ses/services/load-balancer/certs/cert.pem && cp /etc/letsencrypt/live/example.com/privkey.pem /srv/ses/services/load-balancer/certs/key.pem && cd /srv/ses && make prod-deploy"

Stap 5: Uitrollen

5.1 Services Starten

make prod-deploy

Of handmatig:

set -a; source .env.prd; set +a
docker compose --env-file .env.prd -f docker-compose.prod.yml up -d --build

5.2 Implementatie Verifiëren

make prod-ps

Alle 10 containers moeten (healthy) status tonen:

NAME                 STATUS
prod-load-balancer   Up 2 minutes (healthy)
prod-pgbouncer       Up 2 minutes (healthy)
prod-postgres        Up 2 minutes (healthy)
prod-redis           Up 2 minutes (healthy)
prod-ses-proxy-1     Up 2 minutes (healthy)
prod-ses-proxy-2     Up 2 minutes (healthy)
prod-ses-proxy-3     Up 2 minutes (healthy)
prod-ses-server-1    Up 2 minutes (healthy)
prod-ses-server-2    Up 2 minutes (healthy)
prod-ses-server-3    Up 2 minutes (healthy)

5.3 Endpoints Testen

curl https://ems1.example.com/health
curl https://admin.example.com/health

Verwacht antwoord: {"status":"healthy"}


Stap 6: Database Initialiseren

6.1 Migraties Uitvoeren

docker exec prod-ses-server-1 python manage.py migrate

6.2 Superuser Aanmaken

docker exec -it prod-ses-server-1 python manage.py createsuperuser

Volg de prompts om een beheerdersaccount aan te maken.


Stap 7: DNS Configureren

Voeg DNS-records toe voor elk subdomein:

Subdomein Type Waarde
example.com A Server-IP
www.example.com CNAME example.com
ems1.example.com CNAME example.com
ems2.example.com CNAME example.com
admin.example.com CNAME example.com
manuals.example.com CNAME example.com

Stap 8: Manuals Uitrollen

De manuals-site draait als standalone stack, los van de hoofd-SES-services.

8.1 DNS-configuratie

Voeg een DNS-record toe:

Subdomein Type Waarde
manuals.example.com A Server-IP

8.2 SSL-certificaat

Kies één van de twee opties hieronder (moet overeenkomen met uw keuze in Stap 4).

Optie A: Instituutcertificaat

Als u Optie A heeft gekozen in Stap 4, wordt de manuals-site via de hoofd-loadbalancer geserveerd, die al uw instituutcertificaat heeft. Geen extra certificaat nodig — ga door naar 8.3.

Optie B: Let's Encrypt

Als u Optie B heeft gekozen in Stap 4 en de manuals-site op een eigen domein met eigen certificaat wilt:

# Maak certbot-mappen aan
mkdir -p services/manuals/certbot/conf services/manuals/certbot/www

# Vraag certificaat aan (eerst dry-run)
docker run --rm -v "/srv/ses/services/manuals/certbot/conf:/etc/letsencrypt" \
    -v "/srv/ses/services/manuals/certbot/www:/var/www/certbot" \
    certbot/certbot certonly --webroot \
    -w /var/www/certbot \
    -d manuals.example.com \
    --email admin@example.com \
    --agree-tos \
    --no-eff-email \
    --dry-run

# Als dry-run slaagt, voer echt uit
docker run --rm -v "/srv/ses/services/manuals/certbot/conf:/etc/letsencrypt" \
    -v "/srv/ses/services/manuals/certbot/www:/var/www/certbot" \
    certbot/certbot certonly --webroot \
    -w /var/www/certbot \
    -d manuals.example.com \
    --email admin@example.com \
    --agree-tos \
    --no-eff-email

8.3 Manuals Stack Uitrollen

cd /srv/ses/services/manuals
make prod-up

Of handmatig:

docker compose -f services/manuals/docker-compose.manuals.prod.yml up -d --build

8.4 Verifiëren

curl https://manuals.example.com/

Verwacht: HTML-pagina met "Safe Exam Support Manual" titel.

8.5 Auto-vernieuwing (Alleen Let's Encrypt)

Als u Optie B heeft gekozen, voeg toe aan crontab:

0 3 * * * cd /srv/ses && docker compose -f services/manuals/docker-compose.manuals.prod.yml run --rm certbot renew && docker compose -f services/manuals/docker-compose.manuals.prod.yml restart nginx

Als u Optie A heeft gekozen, dekt de auto-vernieuwing cron van de hoofd-loadbalancer (Stap 4.B.4) het manuals-domein ook.

8.6 Makefile-commando's

Commando Beschrijving
make up Bouw + start manuals (lokaal)
make down Stop manuals
make rebuild Forceer herbouw + recreate
make ps Toon containerstatus
make logs Volg logs
make prod-up Start productiestack
make prod-down Stop productiestack
make prod-ps Toon productiestatus
make prod-logs Volg productielogs

Bijwerken

Nieuwste Code Ophalen

cd /srv/ses
git pull origin main

Opnieuw Uitrollen

make prod-deploy

Dit herbouwt en herstart alle containers zonder downtime (rolling update).


Back-up

Database-back-up

docker exec prod-postgres pg_dump -U ses_user ses_db > backup_$(date +%Y%m%d).sql

Geautomatiseerde Back-ups

Voeg toe aan crontab:

0 2 * * * cd /srv/ses && docker exec prod-postgres pg_dump -U ses_user ses_db | gzip > /srv/backups/ses_$(date +\%Y\%m\%d).sql.gz

Monitoring

Logs Bekijken

make prod-logs-server   # Django-logs
make prod-logs-proxy    # Proxy access logs
make prod-logs-lb       # Load balancer logs

Gezondheidscontrole

curl https://ems1.example.com/health

Probleemoplossing

Container Start Niet

docker logs prod-ses-server-1 --tail 50

Database-verbindingsfouten

docker exec prod-pgbouncer cat /var/log/pgbouncer/pgbouncer.log

SSL-certificaatproblemen (Let's encrypt)

certbot certificates
certbot renew --dry-run

Makefile Commando's Referentie

Commando Beschrijving
make prod-deploy Volledige implementatie (pull + build + herstart)
make prod-ps Lijst containers met status
make prod-logs-server Django-server logs
make prod-logs-proxy Proxy access logs
make prod-logs-lb Load balancer logs
make prod-test Tests uitvoeren binnen container
make prod-shell Django-shell
make load-test Load test uitvoeren

Beveiligingschecklist

  • [ ] Alle standaardwachtwoorden gewijzigd in .env.prd
  • [ ] Nieuwe SECRET_KEY gegenereerd
  • [ ] Nieuwe SES_SESSION_TOKEN_SECRET gegenereerd
  • [ ] SSL-certificaten geïnstalleerd en vernieuwen automatisch
  • [ ] Firewall geconfigureerd (alleen 80, 443 open)
  • [ ] Database-back-ups geconfigureerd
  • [ ] Audit-log retentie correct ingesteld
  • [ ] Rate limits geconfigureerd voor uw verkeer