tei-annotator / webservice /nginx.conf
cmboulanger's picture
feat: Add security against malicious clients
a1785f7
# Nginx reverse-proxy configuration for tei-annotator webservice.
#
# All routes are publicly accessible over HTTPS.
#
# Setup:
# 1. sudo cp webservice/nginx.conf /etc/nginx/sites-available/tei-annotator
# 2. sudo ln -s /etc/nginx/sites-available/tei-annotator /etc/nginx/sites-enabled/
# 3. Replace YOUR_DOMAIN with your actual domain (3 occurrences):
# sudo sed -i 's/YOUR_DOMAIN/your.domain.example/g' /etc/nginx/sites-available/tei-annotator
# 4. Install certbot if needed:
# sudo apt install certbot python3-certbot-nginx # Debian/Ubuntu
# sudo dnf install certbot python3-certbot-nginx # RHEL/Fedora
# 5. Obtain a Let's Encrypt certificate using --standalone (nginx must be stopped
# first because the cert does not exist yet and nginx refuses to start with
# missing ssl_certificate paths β€” bootstrap chicken-and-egg):
# sudo systemctl stop nginx
# sudo certbot certonly --standalone -d your.domain.example
# sudo systemctl start nginx
# 6. Verify nginx is running and auto-renewal works:
# sudo systemctl status nginx
# sudo certbot renew --dry-run
#
# To run the webservice as a systemd service, see webservice/tei-annotator.service.
# Rate limit: 6 requests/minute per IP with a burst of 10.
# Covers normal interactive use; blocks scripted automation.
limit_req_zone $binary_remote_addr zone=tei_api:10m rate=6r/m;
upstream tei_annotator {
server 127.0.0.1:8099;
keepalive 16;
}
# ── HTTP: redirect everything to HTTPS ───────────────────────────────────────
server {
listen 80;
listen [::]:80;
server_name YOUR_DOMAIN;
# Let certbot's ACME challenge through, redirect everything else
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
# ── HTTPS ────────────────────────────────────────────────────────────────────
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name YOUR_DOMAIN;
# Paths written by certbot --nginx (or --webroot); update if using a
# different certificate tool or path.
ssl_certificate /etc/letsencrypt/live/YOUR_DOMAIN/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/YOUR_DOMAIN/privkey.pem;
# Modern TLS settings
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
add_header Strict-Transport-Security "max-age=63072000" always;
# Reject request bodies larger than 64 KB to cap token usage.
client_max_body_size 64k;
location / {
limit_req zone=tei_api burst=10 nodelay;
limit_req_status 429;
proxy_pass http://tei_annotator;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_read_timeout 360s;
}
}