Erstellen dynamischer Module für Nginx

Bild


Kürzlich haben wir ein dynamisches Modul für Nginx erstellt. Als alles fertig war, stellte sich heraus, dass unser Modul nicht mit Nginx kompatibel war, das bereits auf dem Server installiert war. Wir konnten keine fertige Lösung für das Problem finden und begannen, es selbst zu bekämpfen. Wir haben viel Zeit verbracht, aber eine neue Erfahrung und vor allem eine funktionierende Lösung gemacht. Was ich gerne teilen möchte.


Beginnen wir mit einer Beschreibung des dynamischen Modulassemblierungsprozesses am Beispiel https://github.com/vozlt/nginx-module-vts . Und dann werden wir zeigen, welcher Fehler auftritt und was damit zu tun ist.


Eingabedaten:
Debian 9 OS
Nginx v1.10.3 aus dem Standard-Debian-Repository. nginx -V Ausgang:


 nginx version: nginx/1.10.3 built with OpenSSL 1.1.0k 28 May 2019 (running with OpenSSL 1.1.1c 28 May 2019) TLS SNI support enabled configure arguments: --with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-DhOtPd/nginx-1.10.3=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-z,relro -Wl,-z,now' --prefix=/usr/share/nginx --conf-path=/etc/ nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path =/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-ipv6 --with-http_ssl_module - -with-http_stub_status_module --with-http_realip_mod ule --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_geoip_module=dynamic --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module= dynamic --with-http_sub_module --with-http_xslt_module=dynamic --with-stream=dynamic --with-stream_ssl_module --with-mail=dynamic --with-mail_ssl_module --add-dynamic-module=/build/nginx-DhOtPd/nginx-1.10.3/debian/modules/nginx-auth-pam --add-dynamic-module=/build/nginx-DhOtPd/nginx-1.10.3/debian/modules/nginx-dav-ext-module --add-dynamic-module=/build/nginx-DhOtPd/nginx-1.10.3/debian/modules/nginx-echo --add-dynamic-module=/build/nginx-DhOtPd/nginx-1.10.3/debian/modules/nginx-upstream-fair --add-dynamic-module=/build/nginx-DhOtPd/nginx -1.10.3/debian/modules/ngx_http_substitutions_filter_module 

Die Ausgabe dieses Befehls enthält Informationen, die für die Zusammenstellung dynamischer Module erforderlich sind, nämlich alles, was nach dem configure arguments: und vor dem ersten - --add-dynamic-module , d. H.


 --with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-DhOtPd/nginx-1.10.3=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-z,relro -Wl,-z,now' --prefix=/usr/share/nginx --conf-path=/etc/ nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path =/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-ipv6 --with-http_ssl_module --with-http_stub_status_module --with-http_realip_mod ule --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_geoip_module=dynamic --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module= dynamic --with-http_sub_module --with-http_xslt_module=dynamic --with-stream=dynamic --with-stream_ssl_module --with-mail=dynamic --with-mail_ssl_module 

Also fahren wir mit der Montage des Moduls fort:


  • Für die Montage ist es bequem, einen Docker-Container zu verwenden, um das Hauptsystem nicht zu überladen. Nehmen Sie das Debian: 9-Image als Grundlage. Um das fertige Modul bequem aus dem Container zu kopieren, können Sie das Volume angeben. Der Befehl zum Starten des Containers sieht in diesem Fall folgendermaßen aus:

 docker run --rm -it -v /tmp/nginx_module:/nginx_module debian:9 bash 

  • Installieren Sie nach dem Starten des Containers die erforderlichen Pakete. Bitte beachten Sie, dass die Pakete gemäß der Ausgabe des Befehls nginx -V ausgewählt werden, sodass Sie möglicherweise einige der Bibliotheken nicht benötigen. In jedem Fall warnt Sie das Konfigurationsskript vor dem Fehlen von Abhängigkeiten:

 apt update apt install git make gcc autoconf wget libpcre3-dev libpcre++-dev zlib1g-dev libxml2-dev libxslt-dev libgd-dev libgeoip-dev 

Das libssl-dev-Paket fehlt in dieser Liste, da der auf dem Server installierte nginx mit der Version 1.1.0k von OpenSSL erstellt wurde und zum Zeitpunkt des Schreibens bei der Installation des libssl-dev-Pakets aus dem Repository die Version von OpenSSL bereits 1.1.0l war. Daher muss der OpenSSL-Quellcode für die richtige Version separat heruntergeladen werden.


  • Laden Sie von der Website http://nginx.org/download nginx die gewünschte Version herunter, in unserem Fall ist es 1.10.3. Laden Sie die OpenSSL-Quellen von der offiziellen Website https://www.openssl.org/source/old herunter und laden Sie den Quellcode des Moduls nginx-module-vts von github herunter.

 cd /usr/local/src/ wget http://nginx.org/download/nginx-1.10.3.tar.gz wget https://www.openssl.org/source/old/1.1.0/openssl-1.1.0k.tar.gz git clone git://github.com/vozlt/nginx-module-vts.git tar xvfz nginx-1.10.3.tar.gz tar xzvf openssl-1.1.0k.tar.gz cd nginx-1.10.3 

  • Jetzt können Sie das Konfigurationsskript ausführen. Als Skriptparameter geben wir alle Parameter aus der Ausgabe des Befehls nginx -V an, über den ich am Anfang des Artikels geschrieben habe. Wir fügen auch den Parameter --add-dynamic-module hinzu, um das Modul nginx-module-vts zu erstellen, und geben den Pfad zum Verzeichnis mit den OpenSSL-Quelldateien über den Parameter --with-openssl an. Der letzte Befehl sieht folgendermaßen aus:

 ./configure --with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-DhOtPd/nginx-1.10.3=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-z,relro -Wl,-z,now' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-ipv6 --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_geoip_module=dynamic --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_sub_module --with-http_xslt_module=dynamic --with-stream=dynamic --with-stream_ssl_module --with-mail=dynamic --with-mail_ssl_module --with-openssl=../openssl-1.1.0k/ --add-dynamic-module=../nginx-module-vts/ 

  • Nachdem das configure funktioniert hat, beginnen wir mit dem Zusammenbau der Module. Wir müssen nicht alle nginx sammeln:

 make modules 

Beachten Sie, dass dieser Befehl nur mit nginx Version 1.9.13 verfügbar ist.


  • Kopieren Sie nach Abschluss des Montagevorgangs die resultierende so-Datei auf das volume , das beim Start des Containers bereitgestellt wurde:

 cp objs/ngx_http_vhost_traffic_status_module.so /nginx_module/ 

  • Als nächstes platzieren wir die Datei auf dem Zielserver. In diesem Fall befindet sich das Verzeichnis mit den Modulen im Pfad /usr/share/nginx/modules . Um das Modul in nginx zu aktivieren, erstellen wir die Datei /etc/nginx/modules-enabled/mod-http-vhost-traffic-status.conf mit folgendem Inhalt:

 load_module modules/ngx_http_vhost_traffic_status_module.so; 

Erstellen Sie einen symbolischen Link zu dieser Datei im Verzeichnis /etc/nginx/modules-enabled .


Nach der Arbeit rufen wir den Befehl nginx -t und ... wir bekommen den Fehler:


 nginx: [emerg] module "/usr/share/nginx/modules/ngx_http_vhost_traffic_status_module.so" is not binary compatible in /etc/nginx/modules-enabled/50-mod-http-vhost-traffic-status.conf:1 

Und hier kommt normalerweise etwas Verwirrung, da die Quellversion und die auf dem Server installierte nginx Version identisch sind, auch die OpenSSL-Versionen. Die Parameter für das configure werden ebenfalls vollständig kopiert. Also, was ist los?


Um dieses Problem zu verstehen, musste ich verstehen, wie nginx prüft, ob das dynamische Modul dafür geeignet ist. Der Code in den nginx Quellen in der src/core/ngx_module.h ( https://github.com/nginx/nginx/blob/master/src/core/ngx_module.h ) ist für diese Überprüfung verantwortlich. Diese Datei enthält eine Reihe von Überprüfungen, in diesem Fall 34, bei denen nginx Variablen der Form NGX_MODULE_SIGNATURE_0 (1,2,3 usw.) NGX_MODULE_SIGNATURE_0 .
Werte 1 oder 0. Als nächstes folgt die Variable NGX_MODULE_SIGNATURE
Hier werden die Ergebnisse aller Prüfungen in einer Zeile zusammengefasst. Dementsprechend besteht das Problem darin, dass die Signaturzeichenfolge des neuen Moduls nicht mit der Signaturzeichenfolge des vorhandenen Nginx übereinstimmt. Um die Werte von Signaturzeichenfolgen zu überprüfen, können Sie die folgenden Befehle verwenden:


  • Die Signaturzeile des erstellten Moduls:

 strings /usr/share/nginx/modules/ngx_http_vhost_traffic_status_module.so| fgrep '8,4,8' 8,4,8,000011111101011111111111110110111 

  • Signaturzeile der auf dem Server installierten nginx Binärdatei:

 strings /usr/sbin/nginx| fgrep '8,4,8' 8,4,8,000011111101011111111111110111111 

Wenn Sie diese Zeilen mit dem bloßen Auge vergleichen, wird deutlich, dass in der Signaturzeile des Moduls die vierte Variable vom Ende 0 war, während nginx hat. Um zu verstehen, was genau im Modul fehlt, müssen Sie auf die src/core/ngx_module.h und finde die vierte Variable vom Ende, es sieht ungefähr so ​​aus:


 #if (NGX_HTTP_REALIP) #define NGX_MODULE_SIGNATURE_29 "1" #else #define NGX_MODULE_SIGNATURE_29 "0" #endif #if (NGX_HTTP_HEADERS) #define NGX_MODULE_SIGNATURE_30 "1" #else #define NGX_MODULE_SIGNATURE_30 "0" #endif #if (NGX_HTTP_DAV) #define NGX_MODULE_SIGNATURE_31 "1" #else #define NGX_MODULE_SIGNATURE_31 "0" #endif #if (NGX_HTTP_CACHE) #define NGX_MODULE_SIGNATURE_32 "1" #else #define NGX_MODULE_SIGNATURE_32 "0" #endif #if (NGX_HTTP_UPSTREAM_ZONE) #define NGX_MODULE_SIGNATURE_33 "1" #else #define NGX_MODULE_SIGNATURE_33 "0" #endif #define NGX_MODULE_SIGNATURE 

Wir interessieren uns für die Variable NGX_HTTP_HEADERS , beim NGX_HTTP_HEADERS nginx es 1 und beim NGX_HTTP_HEADERS des Moduls 0. Damit das Modul mit NGX_HTTP_HEADERS kann, müssen Sie die Konfigurationsdatei im Verzeichnis mit dem Quellcode des Moduls anpassen, indem Sie die Zeile have=NGX_HTTP_HEADERS . auto/have have=NGX_HTTP_HEADERS . auto/have am Anfang der config. Das Folgende ist der Anfang der Konfigurationsdatei, nachdem Sie die Änderungen vorgenommen haben:


 ngx_addon_name=ngx_http_vhost_traffic_status_module have=NGX_STAT_STUB . auto/have have=NGX_HTTP_HEADERS . auto/have ... 

Als nächstes make clean und starten Sie dann configure und make modules . Nach dem Zusammenbau des Moduls überprüfen wir seine Signaturzeichenfolge und stellen fest, dass es jetzt mit der nginx Zeichenfolge übereinstimmt:


 $ strings /usr/sbin/nginx| fgrep '8,4,8' 8,4,8,000011111101011111111111110111111 $ strings /usr/share/nginx/modules/ngx_http_vhost_traffic_status_module.so | fgrep '8,4,8' 8,4,8,000011111101011111111111110111111 

Danach stellt das Modul problemlos eine Verbindung her und Sie können mit nginx erweiterte Statistiken erfassen.


In Ihrem Fall sieht die Signaturzeile möglicherweise anders aus, ebenso wie die Variablen, die für jede Position in dieser Zeile verantwortlich sind. Jetzt können Sie jedoch verstehen, was genau mit der Montage des Moduls nicht stimmt, und das Problem beheben.


Ich hoffe, dieser Artikel spart jemandem ein paar Stunden Zeit, da ich persönlich mehrmals mit dem Problem konfrontiert war, dass das Modul nicht zu nginx passte. Daher habe ich dies in der Regel durch die vollständige Montage von nginx zusammen mit dem richtigen Modul gelöst.


Lesen Sie auch andere Artikel in unserem Blog:


Source: https://habr.com/ru/post/de473578/


All Articles