openresty
(NGINX + Lua
)
Cette fiche opérationnelle décrit la mise en place d'un serveur web openresty
, ou plus simplement Resty
.
Le serveur openResty
est une édition spéciale du serveur NGINX
qui intègre un compilateur « juste à temps » LuaJIT
du langage Lua
. Ce serveur est réputé pour sa rapidité, ses capacités asynchrones et sa consommation mémoire maîtrisée. Son Lua intégré s'appuie lui aussi sur ces qualités, notamment avec ses coroutines. Ainsi, on peut charger une fois pour toutes les programmes Lua composant un site web, et ce dès le démarrage du serveur, sans besoin de devoir ensuite (re-)lire et (re-)compiler en permanence les pages d'un site.
Il n'existe pas de version précompilée pour l'architecture ARM
des cartes Raspberry(ies), nous devrons compiler les sources pour Raspbian, une distribution Debian stretch.
Nous partons d'un serveur Raspian minimal auquel un utilisateur non privilégié or
a été ajouté. Il sera l'utilisateur par défaut du serveur web.
On charge, sous login root
, les outils Lua, liste à compléter à convenance.
apt-get install git luarocks curl libssl-dev libpcre3-dev opensslLe gestionnaire de paquets
luarocks
est l'analogue pour Lua des apt
, pip
et autres npm
.
Rappel : Sous Debian, la numérotation des deux versions des PCRE est piègeuse : libpcre2
est la nouvelle librairie compatible Perl6+ tandis que libpcre3
est l'ancienne compatible Perl5. Nous avons besoin de cette dernière.
Du fait des restrictions imposées par la politique maison de sécurité des systèmes, on relaxe certains des droits portant sur tous les utilisateurs pour les fichiers et répertoires à créer, luarocks
ne les gérant pas spécifiquement
umask 022 # default system policy should be retricted to 027 or even 077
Nous commençons par installer moonscript
. Il s'agir d'un DSL
— Domain Specific Language — qui ajoute une notion d'objet à Lua
ainsi qu'une syntaxe expressive et compacte exprimée par indentation — cf. Python
. Cette lisibilité est vitale pour maintenir à terme les sources des programmes car, pour plagier un célèbre acronyme, il s'agit de programmation WYSIWYC : « ce qu'on voit est ce qu'on Code ». Plus tard, ou à de nouveaux yeux, cela signifiera surtout « ce qu'on voit est bien ce qui a été codé ».
Les paquets Lua nécessaires seront automatiquement téléchargés et compilés
luarocks install moonscript
Passons à lapis
, un framework dans le style de Ruby On Rails ou de django.
luarocks install lapis
Cette phase ne nécessitant aucun privilège, elle se déroulera ici sous le login dédié or
, auquel nous affecterons les workers du démon openresty
. Il sera toutefois possible de le modifier avec la directive user
du fichier de configuration de Resty.
Visiter http://openresty.org/en/download.html puis choisir la dernière version du code source
wget https://openresty.org/download/openresty-1.13.6.2.tar.gz tar xpf openresty-1.13.6.2.tar.gz cd openresty-1.13.6.2/ ./configure \ --build=resty \ --user=or \ --group=or \ --prefix=/opt/openresty \ --conf-path=/etc/openresty/openresty.conf \ --error-log-path=/var/log/openresty/error.log \ --http-log-path=/var/log/openresty/access.log \ --pid-path=/run/openresty.pid \ --lock-path=/run/openresty.log \ --http-client-body-temp-path=/run/openresty/body \ --http-fastcgi-temp-path=/run/openresty/fastcgi \ --http-proxy-temp-path=/run/openresty/proxy \ --http-scgi-temp-path=/run/openresty/scgi \ --http-uwsgi-temp-path=/run/openresty/uwsgi \ --with-pcre-jit \ --with-luajit \ --with-threads \ --with-file-aio \ --with-http_v2_module \ --with-openssl-opt=enable-tls1_3 \ -j$(($(nproc)/2))Adapter, le cas échéant, ces options et d'autres à vos propres besoins. Compiler
make -j $(nproc)
Installer — ici depuis une session en tant que root
du fait que or
n'a pas accès à sudo
ni à d'autres privilèges analogues.
cd /home/or/openresty-1.13.6.2/ && make installquelques tests, toujours sous
root
mkdir /run/openresty chown or:or /run/openresty chmod 0700 /run/openresty /opt/openresty/nginx/sbin/nginx -tEn cas de problème vérifiernginx: the configuration file /etc/openresty/openresty.conf syntax is ok nginx: configuration file /etc/openresty/openresty.conf test is successful/opt/openresty/nginx/sbin/nginx ss -tapine |grep -F nginxLISTEN 0 128 *:80 *:* users:(("nginx",pid=32767,fd=6),("nginx",pid=300,fd=6)) ino:181820 sk:7 <->curl localhost:80(... la page HTML par défaut ...)/opt/openresty/nginx/sbin/nginx -s stop
access.log
et error.log
sous /var/log/openresty
info.scalaire.fr
. Le serveur resty sera seul à l'écouter (sur le port 443/https
) et n'écoutera réciproquement aucune autre adresse. Pour cela voir la fiche opérationnelle associée ;
/etc/openresty/openresty.conf
(très stricte).
F=/etc/openresty/openresty.conf mv -f "$F" "$F".prev cat > "$F" <<EOD.................... user or; worker_processes auto; pcre_jit on; events { worker_connections 100; } http { include mime.types; default_type application/octet-stream; charset utf-8; reset_timedout_connection on; sendfile on; tcp_nopush on; aio threads; directio 1m; #XFS: directio_alignment 4k; keepalive_timeout 60 60; ssl_session_cache shared:SSL:10m; ssl_session_timeout 2h; ssl_session_tickets off; ssl_protocols TLSv1.2 TLSv1.3; # jmp@scalaire : # - waiting : ECDHE-RSA-AES256-GCM-SHA512 : DHE-RSA-AES256-GCM-SHA512 : EECDHE-ECDSA-AES256-GCM-SHA384 # - by end of 2019, all -RSA- ciphers should be deprecated # => ECDSA certificates and (security updated as of nov.2019) # => ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305 : ECDHE-ECDSA-AES128-GCM-SHA256 : ECDHE-ECDSA-AES256-GCM-SHA384 : !ECDHE-ECDSA-AES128-CBC-SHA256 : !ECDHE-ECDSA-AES256-CBC-SHA384'; # SECURITY UPDATE -- nov.2019 (remove _CBC_ see https://robotattack.org/) : ssl_ciphers 'ECDHE-RSA-CHACHA20-POLY1305 : ECDHE-RSA-AES128-GCM-SHA256 : ECDHE-RSA-AES256-GCM-SHA384 : !ECDHE-RSA-AES128-CBC-SHA256 : !ECDHE-RSA-AES256-CBC-SHA384'; ssl_prefer_server_ciphers on; ssl_dhparam /etc/openresty/dhparam.pem; ssl_ecdh_curve secp384r1; # Requires nginx >= 1.1.0 # OCSP Stapling --- ssl_stapling on; ssl_stapling_verify on; # resolver <IP DNS resolver>; # resolver_timeout 5s; # HSTS (15768000 seconds = 6 months) add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload"; add_header X-Frame-Options DENY; # or, relaxed: SAMEORIGINE add_header X-Content-Type-Options nosniff; add_header X-XSS-Protection "1; mode=block"; server { # si IPv4 : listen 80 default_server; # all IPv6 : listen [::]:80 default_server; listen info.scalaire.fr:80; # listen only on this one return 301 https://$host$request_uri; # redirect clear trafic } server { listen info.scalaire.fr:443 ssl http2 reuseport; server_name info.scalaire.fr; ssl_certificate /etc/letsencrypt/live/info.scalaire.fr/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/info.scalaire.fr/privkey.pem; ssl_trusted_certificate /etc/letsencrypt/live/info.scalaire.fr/ca.pem; location / { root /home/or/html; index index.html; } error_page 404 500 502 503 504 /index.html; } } EOD.................... chmod 0660 "$F"
openssl dhparam -out /etc/openresty/dhparam.pem 4096
or
su - or -c "mkdir ~/html && echo '<html><body><h1>A CONFIGURER</h1></body></html>' > ~/html/index.html"
/opt/openresty/nginx/sbin/nginx -t # test config /opt/openresty/nginx/sbin/nginx # daemonize ss -tapine |grep -F nginx # http/80 redirect + 4 workers on the dedicaced IPv6Note : le domaine ne devant plus se résoudre qu'en IPv6, leLISTEN 0 128 2a21:e1b:182:f041:fedd:76f0:2bfe:443:80 :::* users:(("nginx",pid=5150,fd=6),("nginx",pid=5149,fd=6),("nginx",pid=5148,fd=6),("nginx",pid=5147,fd=6),("nginx",pid=5146,fd=6)) ino:197986 sk:13 v6only:1 <-> LISTEN 0 128 2a21:e1b:182:f041:fedd:76f0:2bfe:443:443 :::* users:(("nginx",pid=5150,fd=7),("nginx",pid=5149,fd=7),("nginx",pid=5148,fd=7),("nginx",pid=5147,fd=7),("nginx",pid=5146,fd=7)) ino:197987 sk:14 v6only:1 <-> LISTEN 0 128 2a21:e1b:182:f041:fedd:76f0:2bfe:443:443 :::* users:(("nginx",pid=5150,fd=8),("nginx",pid=5149,fd=8),("nginx",pid=5148,fd=8),("nginx",pid=5147,fd=8),("nginx",pid=5146,fd=8)) ino:197988 sk:15 v6only:1 <-> LISTEN 0 128 2a21:e1b:182:f041:fedd:76f0:2bfe:443:443 :::* users:(("nginx",pid=5150,fd=9),("nginx",pid=5149,fd=9),("nginx",pid=5148,fd=9),("nginx",pid=5147,fd=9),("nginx",pid=5146,fd=9)) ino:197989 sk:16 v6only:1 <-> LISTEN 0 128 2a21:e1b:182:f041:fedd:76f0:2bfe:443:443 :::* users:(("nginx",pid=5150,fd=10),("nginx",pid=5149,fd=10),("nginx",pid=5148,fd=10),("nginx",pid=5147,fd=10),("nginx",pid=5146,fd=10)) ino:197990 sk:17 v6only:1 <->curl -6 info.scalaire.fr # http->https redirect ?<html> <head><title>301 Moved Permanently</title></head> <body bgcolor="white"> <center><h1>301 Moved Permanently</h1></center> <hr><center>openresty/1.13.6.2</center> </body> </html>curl -6 https://info.scalaire.fr # our new page ?<html><body><h1>A CONFIGURER</h1></body></html>
-6
n'est pas nécessaire.
Pour l'aide au diagnostic d'un éventuel problème
openssl s_client -connect info.scalaire.fr:443
systemd
F=/etc/systemd/system/openresty.service cat > "$F" <<EOD......................... # start/stop/reload Resty web server # (jmp@scalaire.fr -- Raspberry Pi3+B) # [Unit] Description=OpenResty (NGINX with Lua engine) web server Documentation=man:nginx(8) After=network.target [Service] Environment="TEMP=/run/openresty" Type=forking PIDFile=/run/openresty.pid ExecStartPre=/bin/mkdir "\$TEMP" ExecStartPre=/bin/chown or:or "\$TEMP" ExecStartPre=/opt/openresty/nginx/sbin/nginx -t -q ExecStart=/opt/openresty/nginx/sbin/nginx ExecReload=/opt/openresty/nginx/sbin/nginx -s reload ExecStop=-/opt/openresty/nginx/sbin/nginx -s stop ExecStopPost=/bin/rm -rf "\$TEMP" TimeoutStopSec=5 KillMode=mixed [Install] WantedBy=multi-user.target EOD......................... chmod 0640 "$F" systemctl daemon-reload systemctl start openresty systemctl status openrestySi tout se déroule bien comme prévu, passer en mode démarrage automatique au reboot
systemctl enable openresty
En plus des liens précédents, une aide au choix des ciphers