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¶
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:
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_KEYgegenereerd - [ ] Nieuwe
SES_SESSION_TOKEN_SECRETgegenereerd - [ ] 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