diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..2d2ecd6 --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +.git/ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7c99b8f..6dffc1a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest env: - TAGS: 1.23.3,latest + NGINX_VERSION: 1.25.2 steps: - uses: actions/checkout@v2 @@ -22,31 +22,25 @@ jobs: if: github.event_name == 'push' && github.ref == 'refs/heads/main' with: registry: docker.io - username: ${{ secrets.DOCKERHUB_USER }} + username: zengxs password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: docker login to ghcr.io - uses: docker/login-action@v2 - if: github.event_name == 'push' && github.ref == 'refs/heads/main' - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - - name: Setup binfmt-support - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 - name: Setup docker buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - name: Generate push tags - run: | - dockerhub_tags=$(echo $TAGS | tr ',' '\n' | sed -e 's#^#docker.io/${{ secrets.DOCKERHUB_USER }}/nginx-quic:#g' | tr '\n' ',' | sed 's#,$##') - ghcr_tags=$(echo $TAGS | tr ',' '\n' | sed -e 's#^#ghcr.io/nginx-quic/nginx-quic:#g' | tr '\n' ',' | sed 's#,$##') - echo "PUSH_TAGS=${dockerhub_tags},${ghcr_tags}" >> $GITHUB_ENV + run: >- + python3 .github/workflows/generate-tags.py + --image-name docker.io/zengxs/nginx + --nginx-version ${{ env.NGINX_VERSION }} + --env-name PUSH_TAGS + >> $GITHUB_ENV - name: Build and push - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v5 with: context: . push: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} @@ -54,3 +48,5 @@ jobs: platforms: linux/amd64,linux/arm64 cache-from: type=gha cache-to: type=gha,mode=max + build-args: | + NGINX_VERSION=${{ env.NGINX_VERSION }} diff --git a/.github/workflows/generate-tags.py b/.github/workflows/generate-tags.py new file mode 100755 index 0000000..435b295 --- /dev/null +++ b/.github/workflows/generate-tags.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 + +import argparse +from datetime import datetime + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--image-name", dest="image_name", required=True) + parser.add_argument("--nginx-version", dest="version", required=True) + parser.add_argument("--env-name", dest="env_name", required=True) + args = parser.parse_args() + + tags = ["latest", args.version, datetime.today().strftime("%Y%m%d")] + + final_tags = [f"{args.image_name}:{tag}" for tag in tags] + print("{}={}".format(args.env_name, ",".join(final_tags))) + + +if __name__ == "__main__": + main() diff --git a/.gitmodules b/.gitmodules index b591a0f..418f483 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,18 +1,12 @@ -[submodule "nginx-quic"] - path = nginx-quic - url = https://github.com/nginx-quic/nginx-quic.git -[submodule "libressl"] - path = libressl - url = https://github.com/libressl-portable/portable.git +[submodule "nginx"] + path = nginx + url = https://github.com/nginx/nginx.git [submodule "modules/ngx_brotli"] path = modules/ngx_brotli url = https://github.com/google/ngx_brotli.git [submodule "modules/njs"] path = modules/njs url = https://github.com/nginx/njs.git -[submodule "modules/zstd-nginx-module"] - path = modules/zstd-nginx-module - url = https://github.com/tokers/zstd-nginx-module.git [submodule "modules/nginx-module-vts"] path = modules/nginx-module-vts url = https://github.com/vozlt/nginx-module-vts.git @@ -31,3 +25,6 @@ [submodule "modules/ngx-fancyindex"] path = modules/ngx-fancyindex url = https://github.com/aperezdc/ngx-fancyindex.git +[submodule "modules/njs-acme"] + path = modules/njs-acme + url = https://github.com/nginx/njs-acme.git diff --git a/Dockerfile b/Dockerfile index ba120f3..64dac29 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -ARG NGINX_VERSION=1.23.3 +ARG NGINX_VERSION=1.25.2 # ==================================================================================================== # FROM nginx:${NGINX_VERSION} AS builder @@ -15,64 +15,24 @@ RUN set -ex \ autoconf \ libtool \ ca-certificates \ - curl - -# build libressl (instead of openssl for QUIC support) -COPY ./libressl /usr/src/libressl -RUN set -ex \ - && cd /usr/src/libressl \ - && ./autogen.sh \ - && ./configure \ - --prefix=/opt/libressl \ - --disable-tests \ - --enable-shared=yes \ - --enable-static=no \ - && make -j$(nproc) install_sw \ -# copy dynamic libraries to /usr/lib so nginx can find them - && find /opt/libressl/lib -name '*.so.*' -exec cp -P {} /usr/lib \; - -# install build dependencies for nginx-quic -RUN set -ex \ - && apt-get install -y --no-install-recommends \ + curl \ + libssl-dev \ libpcre3-dev \ zlib1g-dev -# build nginx-quic -COPY ./nginx-quic /usr/src/nginx-quic -RUN set -ex \ - && cd /usr/src/nginx-quic \ - && echo ./auto/configure \ -# use the same configure arguments as the official nginx build - $( \ - /usr/sbin/nginx -V 2>&1 \ - | grep 'configure arguments:' \ - | sed 's#.*arguments: ##' \ -# but use libressl instead of openssl for QUIC - | sed "s#--with-cc-opt='#--with-cc-opt='-I/opt/libressl/include #" \ - | sed "s#--with-ld-opt='#--with-ld-opt='-L/opt/libressl/lib #" \ - ) \ -# add HTTP/3 and QUIC support - --with-http_v3_module \ - --with-stream_quic_module \ - | bash -x \ -# build nginx - && make -j$(nproc) \ -# just replace /usr/sbin/nginx with the new binary - && cp ./objs/nginx /usr/sbin/nginx - # install build dependencies for additional dynamic modules RUN set -ex \ && apt-get install -y --no-install-recommends \ + libedit-dev \ libgd-dev \ libgeoip-dev \ libmaxminddb-dev \ - libxslt1-dev \ - libzstd-dev + libxslt1-dev -# build dynamic modules +# copy dynamic modules source code +COPY ./nginx /usr/src/nginx COPY ./modules/njs /usr/src/njs COPY ./modules/ngx_brotli /usr/src/ngx_brotli -COPY ./modules/zstd-nginx-module /usr/src/zstd-nginx-module COPY ./modules/nginx-module-vts /usr/src/nginx-module-vts COPY ./modules/ngx_http_geoip2_module \ /usr/src/ngx_http_geoip2_module @@ -81,8 +41,9 @@ COPY ./modules/ngx_http_substitutions_filter_module \ /usr/src/ngx_http_substitutions_filter_module COPY ./modules/headers-more-nginx-module \ /usr/src/headers-more-nginx-module + RUN set -ex \ - && cd /usr/src/nginx-quic \ + && cd /usr/src/nginx \ && echo ./auto/configure \ # all dynamic modules need to be built with the same configure arguments as nginx $(/usr/sbin/nginx -V 2>&1 | grep 'configure arguments:' | sed 's#.*arguments: ##') \ @@ -94,7 +55,6 @@ RUN set -ex \ --add-dynamic-module=/usr/src/njs/nginx \ # third-party dynamic modules --add-dynamic-module=/usr/src/ngx_brotli \ - --add-dynamic-module=/usr/src/zstd-nginx-module \ --add-dynamic-module=/usr/src/nginx-module-vts \ --add-dynamic-module=/usr/src/ngx_http_geoip2_module \ --add-dynamic-module=/usr/src/ngx-fancyindex \ @@ -108,23 +68,51 @@ RUN set -ex \ # move new modules to /usr/lib/nginx/modules && find ./objs -name 'ngx*.so' | xargs -I{} mv {} /usr/lib/nginx/modules/ +# build njs command-line utility +RUN set -ex \ + && cd /usr/src/njs \ + && ./configure \ + && make njs -j$(nproc) \ + && cp ./build/njs /usr/bin/njs \ + && chmod +x /usr/bin/njs + +# download GeoIP2 databases +RUN set -ex \ + && mkdir -p /usr/share/GeoIP \ + && curl -sSL -o /usr/share/GeoIP/GeoLite2-ASN.mmdb \ + https://github.com/P3TERX/GeoLite.mmdb/releases/latest/download/GeoLite2-ASN.mmdb \ + && curl -sSL -o /usr/share/GeoIP/GeoLite2-City.mmdb \ + https://github.com/P3TERX/GeoLite.mmdb/releases/latest/download/GeoLite2-City.mmdb \ + && curl -sSL -o /usr/share/GeoIP/GeoLite2-Country.mmdb \ + https://github.com/P3TERX/GeoLite.mmdb/releases/latest/download/GeoLite2-Country.mmdb + +# ==================================================================================================== # +FROM node AS njs-acme-builder + +WORKDIR /app +COPY ./modules/njs-acme . + +RUN set -ex \ + && npm install \ + && npm run build + # ==================================================================================================== # FROM nginx:${NGINX_VERSION} # remove old modules RUN rm -rf /usr/lib/nginx/modules -# copy nginx binary and modules from builder -COPY --from=builder /usr/sbin/nginx /usr/sbin/nginx +# copy build artifacts from builder stage COPY --from=builder /usr/lib/nginx/modules /usr/lib/nginx/modules -# copy libressl dynamic libraries from builder -COPY --from=builder /usr/lib/libcrypto.so* /usr/lib/ -COPY --from=builder /usr/lib/libssl.so* /usr/lib/ +COPY --from=builder /usr/bin/njs /usr/bin/njs +COPY --from=builder /usr/share/GeoIP /usr/share/GeoIP +COPY --from=njs-acme-builder /app/dist/acme.js /usr/lib/nginx/njs_modules/acme.js # install runtime dependencies RUN set -ex \ && apt-get update -y \ && apt-get install -y --no-install-recommends \ + libpcre3 \ libgd3 \ libgeoip1 \ libxslt1.1 \ diff --git a/README.md b/README.md index e3b859c..23d2b91 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# NGINX docker image for HTTP/3 (QUIC) support +# NGINX docker image with many useful modules [![build][gha-badge]][gha-link] [![dockerhub pulls][dockerhub-pull-badge]][dockerhub-tags] @@ -7,67 +7,26 @@ [![license][license-badge]][license] [![arch][arch-badge]][dockerhub-tags] -[gha-badge]: https://github.com/nginx-quic/docker-nginx-quic/actions/workflows/ci.yml/badge.svg -[gha-link]: https://github.com/nginx-quic/docker-nginx-quic/actions/workflows/ci.yml -[dockerhub-tags]: https://hub.docker.com/r/zengxs/nginx-quic/tags -[dockerhub-pull-badge]: https://img.shields.io/docker/pulls/zengxs/nginx-quic?logo=docker -[dockerhub-size-badge]: https://img.shields.io/docker/image-size/zengxs/nginx-quic?logo=docker -[dockerhub-version-badge]: https://img.shields.io/docker/v/zengxs/nginx-quic?logo=docker -[license-badge]: https://img.shields.io/github/license/nginx-quic/nginx-quic +[gha-badge]: https://github.com/zengxs/docker-nginx/actions/workflows/ci.yml/badge.svg +[gha-link]: https://github.com/zengxs/docker-nginx/actions/workflows/ci.yml +[dockerhub-tags]: https://hub.docker.com/r/zengxs/nginx/tags +[dockerhub-pull-badge]: https://img.shields.io/docker/pulls/zengxs/nginx?logo=docker +[dockerhub-size-badge]: https://img.shields.io/docker/image-size/zengxs/nginx?logo=docker +[dockerhub-version-badge]: https://img.shields.io/docker/v/zengxs/nginx?logo=docker +[license-badge]: https://img.shields.io/github/license/zengxs/docker-nginx [license]: ./LICENSE [arch-badge]: https://img.shields.io/badge/arch-x86__64%20%7C%20arm64-lightgrey -[libressl]: https://www.libressl.org/ -[quictls]: https://github.com/quictls/openssl/ -[boringssl]: https://boringssl.googlesource.com/boringssl/ -Drop-in replacement for the official NGINX docker image, with HTTP/3 (QUIC) support. +Drop-in replacement for the official nginx image with many useful modules. -## What is this image? +You can use it just like the official image without any changes, but you can enjoy many +useful modules that are not included in the official image by adding some simple `load_module` +directives in your NGINX configuration. -NGINX now has support for HTTP/3 (QUIC), but the official docker image doesn't have it. -this image is a drop-in replacement for the official image, with HTTP/3 (QUIC) support. - -This image is based on the official NGINX docker image and adds support for HTTP/3 (QUIC) -using the [LibreSSL][libressl] library. The image use the same build configuration as the -official image, and just update the NGINX binary to support HTTP/3. - -Also, the image adds some popular third-party modules, they are linked dynamically, that -means there will be no overhead if you don't use them. But if you want to use them, you -don't need to build your own image, just add some `load_module` directives in your NGINX -configuration file. - -Other than that, the image is the same as the official one, so you can use it as a drop-in -replacement for the official image. - -## Why LibreSSL? - -At this moment, NGINX can use three SSL implementations to support HTTP/3 (QUIC): -[BoringSSL][boringssl], [QuicTLS][quictls] and [LibreSSL][libressl]. - -BoringSSL is Google's fork of OpenSSL and it is used by Chromium and Google's other projects. -It is not aims server-side use, and it documented: - -> 1. that is designed to meet Google's needs. -> 2. it is not intended for general use. -> 3. We don't recommend that third parties depend upon it. - -QuicTLS is a fork of OpenSSL enabled with QUIC support, but it's not ready for production. - -LibreSSL is a fork of OpenSSL, it is a security-focused, modern version of the TLS/crypto -library. It is a drop-in replacement for OpenSSL, and it is used by many projects, such as -OpenSSH, OpenBSD, macOS, etc. - -So I think LibreSSL is the best choice for this image. - -## How to pull the image? - -```sh -# Pull the image from GitHub Container Registry -docker pull ghcr.io/nginx-quic/nginx-quic - -# Or pull the image from Docker Hub -docker pull zengxs/nginx-quic -``` +> **NOTE**: This image is based on the official image debian variant, and all default +> configurations are the same as the official image. So you must explicitly enable the +> modules you want to use, otherwise this image will not be different from the official +> image. ## How to use this image? @@ -80,8 +39,8 @@ Change your docker-compose file like this: version: '3.9' services: nginx: -- image: nginx:1.23.3 -+ image: ghcr.io/nginx-quic/nginx-quic:1.23.3 +- image: nginx:1.25.2 ++ image: zengxs/nginx:1.25.2 ``` Or change your docker command like this: @@ -93,45 +52,37 @@ Or change your docker command like this: -v $PWD/conf.d:/etc/nginx/conf.d \ -v $PWD/certs:/etc/nginx/certs \ -p 80:80 -p 443:443 \ -- nginx:1.23.3 -+ ghcr.io/nginx-quic/nginx-quic:1.23.3 +- nginx:1.25.2 ++ zengxs/nginx:1.25.2 ``` -> **NOTE:** -> -> The image is based on the official `debian` variant (default variant), so if you are -> using the `alpine` variant before, may this image is not a drop-in replacement for you. -> -> But if you are not doing anything special in your image, you can just replace the image -> name, and it should work. -> -> The `debian` variant is the default official variant, it not only has the best compatibility, -> but also has the best performance. So I think it is the best choice for this image. - ## Third-party modules -| Module | Description | Dynamic module file name | -| ------------------------------------------------------- | ---------------------------------------------- | --------------------------------------------------------------------- | -| [ngx_brotli][mod-brotli] | Brotli compression module maintained by Google | ngx_http_brotli_filter_module.so
ngx_http_brotli_static_module.so | -| [zstd-nginx-module][mod-zstd] | Zstandard compression module | ngx_http_zstd_filter_module.so
ngx_http_zstd_static_module.so | -| [headers-more-nginx-module][mod-headers-more] | More set of headers for NGINX | ngx_http_headers_more_filter_module.so | -| [nginx-module-vts][mod-vts] | Nginx virtual host traffic status module | ngx_http_vhost_traffic_status_module.so | -| [ngx_http_geoip2_module][mod-geoip2] | GeoIP2 module for NGINX | ngx_http_geoip2_module.so
ngx_stream_geoip2_module.so | -| [ngx-fancyindex][mod-fancyindex] | Fancy indexes module for NGINX | ngx_http_fancyindex_module.so | -| [ngx_http_substitutions_filter_module][mod-subs-filter] | Substitutions filter module for NGINX | ngx_http_subs_filter_module.so | +### Dynamic modules + +| Module | Description | Dynamic module file name | +| ------------------------------------------------------- | -------------------------------------------------------------- | --------------------------------------------------------------------- | +| [ngx_brotli][mod-brotli] | Brotli compression module maintained by Google | ngx_http_brotli_filter_module.so
ngx_http_brotli_static_module.so | +| [headers-more-nginx-module][mod-headers-more] | More set of headers for NGINX | ngx_http_headers_more_filter_module.so | +| [nginx-module-vts][mod-vts] | Nginx virtual host traffic status module | ngx_http_vhost_traffic_status_module.so | +| [ngx_http_geoip2_module][mod-geoip2] | GeoIP2 module for NGINX (GeoLite2 database included[^geolite]) | ngx_http_geoip2_module.so
ngx_stream_geoip2_module.so | +| [ngx-fancyindex][mod-fancyindex] | Fancy indexes module for NGINX | ngx_http_fancyindex_module.so | +| [ngx_http_substitutions_filter_module][mod-subs-filter] | Substitutions filter module for NGINX | ngx_http_subs_filter_module.so | [mod-brotli]: https://github.com/google/ngx_brotli -[mod-zstd]: https://github.com/tokers/zstd-nginx-module [mod-headers-more]: https://github.com/openresty/headers-more-nginx-module [mod-vts]: https://github.com/vozlt/nginx-module-vts [mod-geoip2]: https://github.com/leev/ngx_http_geoip2_module [mod-fancyindex]: https://github.com/aperezdc/ngx-fancyindex [mod-subs-filter]: https://github.com/yaoweibin/ngx_http_substitutions_filter_module -Also you can ls the `/usr/lib/nginx/modules` directory to see all the available dynamic modules: +[^geolite]: GeoLite2 database is located at `/usr/share/GeoIP/GeoLite2-{ASN,City,Country}.mmdb`. + +All dynamic modules are installed in `/usr/lib/nginx/modules` directory. You can use the +following command to list them: ```sh -docker run --rm -it ghcr.io/nginx-quic/nginx-quic ls -lh /usr/lib/nginx/modules/ +docker run --rm -it zengxs/nginx ls -lh /usr/lib/nginx/modules/ ``` You can enable them by simply adding some `load_module` directives in your NGINX configuration: @@ -141,6 +92,38 @@ load_module modules/ngx_http_brotli_filter_module.so; load_module modules/ngx_http_brotli_static_module.so; ``` +### `njs` modules + +| Module | Description | JS module file name | +| ------------------------ | --------------------- | ------------------- | +| [njs-acme][mod-njs-acme] | ACME module for NGINX | `acme.js` | + +[mod-njs-acme]: https://github.com/nginx/njs-acme + +All `njs` modules are installed in `/usr/share/nginx/njs_modules` directory. You can use the +following command to list them: + +```sh +docker run --rm -it zengxs/nginx ls -lh /usr/share/nginx/njs_modules/ +``` + +You must enable the `njs` module to use `njs` modules: + +```nginx +# load dynamic modules +load_module modules/ngx_http_js_module.so; +load_module modules/ngx_stream_js_module.so; + +# set search path for njs +js_path /usr/share/nginx/njs_modules; +``` + +Then you can import njs modules in your NGINX configuration: + +```nginx +js_import acme from 'acme.js'; +``` + ## License All submodules are licensed under their own licenses. Other files are licensed under the diff --git a/libressl b/libressl deleted file mode 160000 index aa1f9b1..0000000 --- a/libressl +++ /dev/null @@ -1 +0,0 @@ -Subproject commit aa1f9b11664ac41f304b638ec259d937fee6281e diff --git a/modules/ngx_brotli b/modules/ngx_brotli index 6e975bc..63ca02a 160000 --- a/modules/ngx_brotli +++ b/modules/ngx_brotli @@ -1 +1 @@ -Subproject commit 6e975bcb015f62e1f303054897783355e2a877dc +Subproject commit 63ca02abdcf79c9e788d2eedcc388d2335902e52 diff --git a/modules/ngx_http_geoip2_module b/modules/ngx_http_geoip2_module index cbaa354..a607a41 160000 --- a/modules/ngx_http_geoip2_module +++ b/modules/ngx_http_geoip2_module @@ -1 +1 @@ -Subproject commit cbaa35461c62a99d2577e6bae3273492502d8769 +Subproject commit a607a41a8115fecfc05b5c283c81532a3d605425 diff --git a/modules/njs b/modules/njs index 9645655..5129f50 160000 --- a/modules/njs +++ b/modules/njs @@ -1 +1 @@ -Subproject commit 9645655a22d588cebb27bda9c455c8fac7b74ceb +Subproject commit 5129f50040568b2e938ced0b10431b030a453170 diff --git a/modules/njs-acme b/modules/njs-acme new file mode 160000 index 0000000..5936065 --- /dev/null +++ b/modules/njs-acme @@ -0,0 +1 @@ +Subproject commit 59360653ced6feb9c24523f193baa2da432237ff diff --git a/modules/zstd-nginx-module b/modules/zstd-nginx-module deleted file mode 160000 index 1e0fa0b..0000000 --- a/modules/zstd-nginx-module +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1e0fa0bfb995e72f8f7e4c0153025c3306f1a5cc diff --git a/nginx b/nginx new file mode 160000 index 0000000..b489ba8 --- /dev/null +++ b/nginx @@ -0,0 +1 @@ +Subproject commit b489ba83e9be446923facfe1a2fe392be3095d1f diff --git a/nginx-quic b/nginx-quic deleted file mode 160000 index a1bb12e..0000000 --- a/nginx-quic +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a1bb12e14ee86fdac2877c3a834b604f5bc522ae