从源代码构建 Nginx

首先

因为有机会编写Nginx模块,所以现在我来写一下从源代码构建Nginx的方法。虽然现在有点晚了。本来我想一直写到制作模块的部分,但是进展不大,所以暂时搁置了。这篇文章比较简单。

如果只需要教授指令的人,请点击这里,写字不必要。

行动指南

根据我看到的 Qiita 上的其他 nginx 构建文章,似乎有一种名为 nginx-build 的构建辅助工具,但在本文中,我会手动逐个下载。我还会使用源代码而非预编译软件包来构建所需的库。

如果在我手上的 Ubuntu 22.04 上使用 “apt install nginx” 安装 nginx,则构建选项如下。我计划将其配置成相同的构建,并替换正在运行的二进制文件。尽管有些模块我不打算使用,但暂时还是会安装它们。然而,不管正在运行的版本如何,我会使用最新版本的 nginx 和各个库。

$ nginx -V
nginx version: nginx/1.18.0 (Ubuntu)
built with OpenSSL 3.0.2 15 Mar 2022
TLS SNI support enabled
configure arguments:
 --with-cc-opt='-g -O2 -ffile-prefix-map=/build/nginx-d8gVax/nginx-1.18.0=. -flto=auto -ffat-lto-objects -flto=auto -ffat-lto-objects -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2'
 --with-ld-opt='-Wl,-Bsymbolic-functions -flto=auto -ffat-lto-objects -flto=auto -Wl,-z,relro -Wl,-z,now -fPIC'
 --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-compat
 --with-debug
 --with-pcre-jit
 --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
 --add-dynamic-module=/build/nginx-d8gVax/nginx-1.18.0/debian/modules/http-geoip2
 --with-http_addition_module
 --with-http_gunzip_module
 --with-http_gzip_static_module
 --with-http_sub_module

下载列表

我先列出一份清单。现在全部都放在 GitHub 上,这很方便。在我的环境中,所有的源代码都放在 /data/src 目录下,安装的路径是 /data/bin。

ModuleVersion (as of 2023-02-20)URLDepends onNginxrelease-1.23.3https://github.com/nginx/nginx-ngx_http_geoip2_module3.4https://github.com/leev/ngx_http_geoip2_module-libmaxminddb1.7.1https://github.com/maxmind/libmaxminddbngx_http_geoip2_moduleOpenSSLopenssl-3.0.8https://github.com/openssl/openssl/ngx_http_ssl_modulezlibv1.2.13https://github.com/madler/zlib.gitngx_http_gzip_modulePCRE2pcre2-10.42https://github.com/PCRE2Project/pcre2ngx_http_rewrite_module

工具

由于使用全新的Ubuntu,我们将从构建工具进行安装。为了构建libmaxminddb,我们需要安装autoconf,automake和libtool。

$ sudo apt install build-essential autoconf automake libtool

下载

按照前面提到的表格,只需简单地执行 git clone 命令。很简单。由于 libmaxminddb 包含子模块,所以需要使用 –recursive 参数。

$ cd /data/src
$ git clone --depth=1 --branch=release-1.23.3 https://github.com/nginx/nginx.git
$ git clone --depth=1 --branch=3.4 https://github.com/leev/ngx_http_geoip2_module.git
$ git clone --depth=1 --branch=1.7.1 --recursive https://github.com/maxmind/libmaxminddb
$ git clone --depth=1 --branch=openssl-3.0.8 https://github.com/openssl/openssl.git
$ git clone --depth=1 --branch=v1.2.13 https://github.com/madler/zlib.git
$ git clone --depth=1 --branch=pcre2-10.42 https://github.com/PCRE2Project/pcre2.git

关于 pcre2,您需要事先运行 autogen。如果忘记了,会因为找不到 configure 文件而导致构建 nginx 时产生错误提示。

$ cd /data/src/pcre2
$ ./autogen.sh

只需下载源代码并在配置nginx时传递路径即可一次性构建所需的依赖模块。但是,nginx的子模块,即geoip2模块,依赖于libmaxminddb,并不会自动构建,所以需要事先自己构建。

$ cd /data/src/libmaxminddb
$ ./bootstrap
$ ./configure --prefix=/data/bin/libmaxminddb
$ make -j8
$ make install

建造

基本上,我们会将通过 nginx -V 输出的选项传递给 auto/configure,但会更改以下依赖于构建环境的部分。

    • コンパイルオプションから -ffile-prefix-map 削除

 

    • コンパイルオプションに libmaxminddb のヘッダーパスを追加

 

    • リンカオプションに libmaxminddb のライブラリパスを追加

 

    • ngx_http_geoip2_module のソースコードパスを変更

 

    –with-pcre、–with-openssl、–with-zlib を追加

只需要进行常规的配置-编译-装载步骤,不需要执行 “make install” 步骤。原因是因为 –prefix 设为 /usr/share/nginx,需要使用 sudo 运行 make install,但我们不希望意外地替换掉不需要的文件。

如果想要以更加干净的方式运行“make install”,最好将–prefix、–conf-path、–modules-path这些选项修改为不需要sudo权限的目录,例如/data/bin。

$ cd /data/src/nginx
# auto/configure \
 --with-cc-opt='-g -O2 -flto=auto -ffat-lto-objects -flto=auto -ffat-lto-objects -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2 -I/data/bin/libmaxminddb/include' \
 --with-ld-opt='-Wl,-Bsymbolic-functions -flto=auto -ffat-lto-objects -flto=auto -Wl,-z,relro -Wl,-z,now -fPIC -L/data/bin/libmaxminddb/lib' \
 --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-compat \
 --with-debug \
 --with-pcre-jit \
 --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 \
 --add-dynamic-module=/data/src/ngx_http_geoip2_module \
 --with-http_addition_module \
 --with-http_gunzip_module \
 --with-http_gzip_static_module \
 --with-http_sub_module \
 --with-pcre=/data/src/pcre2 \
 --with-openssl=/data/src/openssl \
 --with-zlib=/data/src/zlib
$ make -j8

由於二進制文件被創建在objs/nginx和objs/ngx_http_geoip2_module.so中,因此將替換正在運行的二進制文件。值得注意的是,apt安裝的軟體包中除了geoip2外還包含其他動態模塊,在安裝後的狀態下將從/etc/nginx/modules-enabled目錄下的conf文件中加載所有模塊。由於我們將nginx版本從1.18.0升級到1.23.3,因此通過apt安裝的動態模塊與我們編譯的geoip2模塊無法混合。如果使用了動態模塊,則需要重新編譯所有模塊。如果沒有使用,我認為可以將/etc/nginx/modules-enabled目錄下的conf文件備份到其他地方,不必煩惱重新加載。

尝试

为了测试,运行构建的ssl和geoip2模块。它可以获取客户端IP的国家信息并输出到访问日志中。

我们需要在 /etc/nginx/nginx.conf 的 http 部分中添加以下配置。配置内容几乎与 https://github.com/leev/ngx_http_geoip2_module 上写的完全一样。mmdb 文件是从 http://dev.maxmind.com/geoip/geoip2/geolite2/ 下载的。

http {
  ...

  geoip2 /data/conf/GeoLite2-Country.mmdb {
    auto_reload 5m;
    $geoip2_data_country_code default=? country iso_code;
    $geoip2_data_country_name default=? country names en;
  }
  geoip2 /data/conf/GeoLite2-City.mmdb {
    auto_reload 5m;
    $geoip2_data_city_name default=? city names en;
  }
  log_format geolog
    '[$time_local] $remote_addr'
    ' ($geoip2_data_country_code $geoip2_data_country_name $geoip2_data_city_name)'
    ' "$request" $status $bytes_sent $request_time "$http_user_agent"';

  ...
}

此外,您可以将以下虚拟主机设置内容作为单独的 conf 文件,或将其写入 /etc/nginx/nginx.conf 文件中。

server {
  listen 443 ssl;
  ssl_certificate /data/conf/cert.pem;
  ssl_certificate_key /data/conf/privkey.pem;
  access_log /var/log/nginx/ssl-access.log geolog;
  error_log /var/log/nginx/ssl-error.log;
  location / {
    proxy_pass http://localhost:8000;
  }
}

当从内部 IP 和 https://reqbin.com/ 访问此 SSL 服务器时,以下是日志记录的内容。看起来 geoip2 正在运行。

$ sudo tail -f /var/log/nginx/ssl-access.log
[19/Feb/2023:19:28:04 -0800] 10.0.0.99 (? ? ?) "GET / HTTP/1.1" 200 850 0.000 "curl/7.83.1"
[19/Feb/2023:19:29:34 -0800] 10.0.0.99 (? ? ?) "GET / HTTP/1.1" 200 850 0.000 "curl/7.83.1"
[19/Feb/2023:19:30:10 -0800] 206.189.205.251 (US United States North Bergen) "GET / HTTP/1.1" 200 645 0.000 "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/110.0 X-Middleton/1"
[19/Feb/2023:19:32:53 -0800] 206.189.205.251 (US United States North Bergen) "GET / HTTP/1.1" 200 645 0.000 "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/110.0 X-Middleton/1"

命令列表

mkdir /data/src
mkdir /data/bin

sudo apt update -y
sudo apt install build-essential autoconf automake libtool -y

cd /data/src
git clone --depth=1 --branch=release-1.23.3 https://github.com/nginx/nginx.git
git clone --depth=1 --branch=3.4 https://github.com/leev/ngx_http_geoip2_module.git
git clone --depth=1 --branch=1.7.1 --recursive https://github.com/maxmind/libmaxminddb
git clone --depth=1 --branch=openssl-3.0.8 https://github.com/openssl/openssl.git
git clone --depth=1 --branch=v1.2.13 https://github.com/madler/zlib.git
git clone --depth=1 --branch=pcre2-10.42 https://github.com/PCRE2Project/pcre2.git

cd /data/src/pcre2
./autogen.sh

cd /data/src/libmaxminddb
./bootstrap
./configure --prefix=/data/bin/libmaxminddb
make -j8
make install

cd /data/src/nginx
auto/configure \
 --with-cc-opt='-g -O2 -flto=auto -ffat-lto-objects -flto=auto -ffat-lto-objects -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2 -I/data/bin/libmaxminddb/include' \
 --with-ld-opt='-Wl,-Bsymbolic-functions -flto=auto -ffat-lto-objects -flto=auto -Wl,-z,relro -Wl,-z,now -fPIC -L/data/bin/libmaxminddb/lib' \
 --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-compat \
 --with-debug \
 --with-pcre-jit \
 --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 \
 --add-dynamic-module=/data/src/ngx_http_geoip2_module \
 --with-http_addition_module \
 --with-http_gunzip_module \
 --with-http_gzip_static_module \
 --with-http_sub_module \
 --with-pcre=/data/src/pcre2 \
 --with-openssl=/data/src/openssl \
 --with-zlib=/data/src/zlib
make -j8
bannerAds