diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000..d8b19f81d --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,6 @@ +##################### +# Main global owner # +##################### + +* @nginx/syseng + diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 000000000..aa0fb9e13 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,62 @@ +--- +name: 🐛 Bug report +description: Create a report to help us improve +labels: bug +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report! + + Before you continue filling out this report, please take a moment to check that your bug has not been [already reported on GitHub][issue search] 🙌 + + Remember to redact any sensitive information such as authentication credentials and/or license keys! + + [issue search]: ../search?q=is%3Aissue&type=issues + + - type: textarea + id: overview + attributes: + label: Bug Overview + description: A clear and concise overview of the bug. + placeholder: When I do "X" with the NGINX Docker image, "Y" happens instead of "Z". + validations: + required: true + + - type: textarea + id: behavior + attributes: + label: Expected Behavior + description: A clear and concise description of what you expected to happen. + placeholder: When I do "X" with the NGINX Docker image, I expect "Z" to happen. + validations: + required: true + + - type: textarea + id: steps + attributes: + label: Steps to Reproduce the Bug + description: Detail the series of steps required to reproduce the bug. + placeholder: When I run the Docker NGINX image using [...], the image fails with an error message. If I check the terminal outputs and/or logs, I see the following error info. + validations: + required: true + + - type: textarea + id: environment + attributes: + label: Environment Details + description: Please provide details about your environment. + value: | + - Version/release of Docker and method of installation (e.g. Docker Desktop / Docker Server) + - Version of the Docker NGINX image or specific commit: [e.g. 1.4.3/commit hash] + - Target deployment platform: [e.g. OpenShift/Kubernetes/Docker Compose/local cluster/etc...] + - Target OS: [e.g. RHEL 9/Ubuntu 24.04/etc...] + validations: + required: true + + - type: textarea + id: context + attributes: + label: Additional Context + description: Add any other context about the problem here. + placeholder: Feel free to add any other context/information/screenshots/etc... that you think might be relevant to this issue in here. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..3f7850f70 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,12 @@ +--- +blank_issues_enabled: false +contact_links: + - name: 💬 Talk to the NGINX community! + url: https://community.nginx.org + about: A community forum for NGINX users, developers, and contributors + - name: 📝 Code of Conduct + url: https://www.contributor-covenant.org/version/2/1/code_of_conduct + about: NGINX follows the Contributor Covenant Code of Conduct to ensure a safe and inclusive community + - name: 💼 For commercial & enterprise users + url: https://www.f5.com/products/nginx + about: F5 offers a wide range of NGINX products for commercial & enterprise users diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 000000000..ee20eec9f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,41 @@ +--- +name: ✨ Feature request +description: Suggest an idea for this project +labels: enhancement +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this feature request! + + Before you continue filling out this request, please take a moment to check that your feature has not been [already requested on GitHub][issue search] 🙌 + + **Note:** If you are seeking community support or have a question, please consider starting a new thread via [GitHub discussions][discussions] or the [NGINX Community forum][forum]. + + [issue search]: ../search?q=is%3Aissue&type=issues + + [discussions]: ../discussions + [forum]: https://community.nginx.org + + - type: textarea + id: overview + attributes: + label: Feature Overview + description: A clear and concise description of what the feature request is. + placeholder: I would like the Docker NGINX image to be able to do "X". + validations: + required: true + + - type: textarea + id: alternatives + attributes: + label: Alternatives Considered + description: Detail any potential alternative solutions/workarounds you've used or considered. + placeholder: I have done/might be able to do "X" in the Docker NGINX image by doing "Y". + + - type: textarea + id: context + attributes: + label: Additional Context + description: Add any other context about the problem here. + placeholder: Feel free to add any other context/information/screenshots/etc... that you think might be relevant to this feature request here. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 000000000..0dc5899cf --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,14 @@ +### Proposed changes + +Describe the use case and detail of the change. If this PR addresses an issue on GitHub, make sure to include a link to that issue using one of the [supported keywords](https://docs.github.com/en/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue) in this PR's description or commit message. + +### Checklist + +Before creating a PR, run through this checklist and mark each as complete: + +- [ ] I have read the [contributing guidelines](/CONTRIBUTING.md) +- [ ] I have signed the [F5 Contributor License Agreement (CLA)](https://github.com/f5/f5-cla/blob/main/docs/f5_cla.md) +- [ ] I have run `./update.sh` and ensured all entrypoint/Dockerfile template changes have been applied to the relevant image entrypoint scripts & Dockerfiles +- [ ] If applicable, I have added tests that prove my fix is effective or that my feature works +- [ ] If applicable, I have checked that any relevant tests pass after adding my changes +- [ ] I have updated any relevant documentation ([`README.md`](/README.md) and/or [`modules/README.md`](/modules/README.md)) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..37d7a6218 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,49 @@ +name: GitHub CI + +on: + pull_request: + push: + schedule: + - cron: 0 10 * * Mon + +defaults: + run: + shell: 'bash -Eeuo pipefail -x {0}' + +jobs: + + generate-jobs: + name: Generate Jobs + runs-on: ubuntu-latest + outputs: + strategy: ${{ steps.generate-jobs.outputs.strategy }} + steps: + - uses: actions/checkout@v3 + - uses: docker-library/bashbrew@v0.1.12 + - id: generate-jobs + name: Generate Jobs + run: | + strategy="$(GITHUB_REPOSITORY=nginx "$BASHBREW_SCRIPTS/github-actions/generate.sh")" + strategy="$(GITHUB_REPOSITORY=nginx "$BASHBREW_SCRIPTS/github-actions/munge-i386.sh" -c <<<"$strategy")" + echo "strategy=$strategy" >> "$GITHUB_OUTPUT" + jq . <<<"$strategy" # sanity check / debugging aid + + test: + needs: generate-jobs + strategy: ${{ fromJson(needs.generate-jobs.outputs.strategy) }} + name: ${{ matrix.name }} + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v3 + - name: Prepare Environment + run: ${{ matrix.runs.prepare }} + - name: Pull Dependencies + run: ${{ matrix.runs.pull }} + - name: Build ${{ matrix.name }} + run: ${{ matrix.runs.build }} + - name: History ${{ matrix.name }} + run: ${{ matrix.runs.history }} + - name: Test ${{ matrix.name }} + run: ${{ matrix.runs.test }} + - name: '"docker images"' + run: ${{ matrix.runs.images }} diff --git a/.github/workflows/f5_cla.yml b/.github/workflows/f5_cla.yml new file mode 100644 index 000000000..43e473eab --- /dev/null +++ b/.github/workflows/f5_cla.yml @@ -0,0 +1,41 @@ +--- +name: F5 CLA +on: + issue_comment: + types: [created] + pull_request_target: + types: [opened, closed, synchronize] +permissions: read-all +jobs: + f5-cla: + name: F5 CLA + runs-on: ubuntu-24.04 + permissions: + actions: write + pull-requests: write + statuses: write + steps: + - name: Run F5 Contributor License Agreement (CLA) assistant + if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have hereby read the F5 CLA and agree to its terms') || github.event_name == 'pull_request_target' + uses: contributor-assistant/github-action@ca4a40a7d1004f18d9960b404b97e5f30a505a08 # v2.6.1 + with: + # Path to the CLA document. + path-to-document: https://github.com/f5/f5-cla/blob/main/docs/f5_cla.md + # Custom CLA messages. + custom-notsigned-prcomment: '🎉 Thank you for your contribution! It appears you have not yet signed the [F5 Contributor License Agreement (CLA)](https://github.com/f5/f5-cla/blob/main/docs/f5_cla.md), which is required for your changes to be incorporated into an F5 Open Source Software (OSS) project. Please kindly read the [F5 CLA](https://github.com/f5/f5-cla/blob/main/docs/f5_cla.md) and reply on a new comment with the following text to agree:' + custom-pr-sign-comment: 'I have hereby read the F5 CLA and agree to its terms' + custom-allsigned-prcomment: '✅ All required contributors have signed the F5 CLA for this PR. Thank you!' + # Remote repository storing CLA signatures. + remote-organization-name: f5 + remote-repository-name: f5-cla-data + # Branch where CLA signatures are stored. + branch: main + path-to-signatures: signatures/signatures.json + # Comma separated list of usernames for maintainers or any other individuals who should not be prompted for a CLA. + # NOTE: You will want to edit the usernames to suit your project needs. + allowlist: bot* + # Do not lock PRs after a merge. + lock-pullrequest-aftermerge: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PERSONAL_ACCESS_TOKEN: ${{ secrets.F5_CLA_TOKEN }} diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml new file mode 100644 index 000000000..99dc98601 --- /dev/null +++ b/.github/workflows/sync.yml @@ -0,0 +1,44 @@ +name: Sync DockerHub with AWS ECR + +on: + workflow_dispatch: + schedule: + - cron: 23 20 * * * + +defaults: + run: + shell: 'bash -Eeuo pipefail -x {0}' + +jobs: + sync-awsecr: + name: Sync Docker Hub to AWS ECR Public + runs-on: ubuntu-24.04 + permissions: + id-token: write + contents: read + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2 + with: + role-to-assume: ${{ secrets.AWS_ROLE_PUBLIC_ECR }} + aws-region: us-east-1 + + - name: Login to Amazon ECR Public + id: login-ecr-public + uses: aws-actions/amazon-ecr-login@062b18b96a7aff071d4dc91bc00c4c1a7945b076 # v2.0.1 + with: + registry-type: public + + - name: Login to Docker Hub + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build, tag, and push docker image to Amazon ECR Public + run: | + ./sync-awsecr.sh > sync-real.sh + chmod +x sync-real.sh + ./sync-real.sh diff --git a/.test/config.sh b/.test/config.sh new file mode 100755 index 000000000..e371f4043 --- /dev/null +++ b/.test/config.sh @@ -0,0 +1,11 @@ +imageTests+=( + [nginx]=' + ipv6 + static + templates + templates-resolver + templates-resolver-ipv6 + workers + modules + ' +) diff --git a/.test/tests/ipv6/expected-std-out.txt b/.test/tests/ipv6/expected-std-out.txt new file mode 100644 index 000000000..f16a08766 --- /dev/null +++ b/.test/tests/ipv6/expected-std-out.txt @@ -0,0 +1,2 @@ +

Welcome to nginx!

+10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf diff --git a/.test/tests/ipv6/run.sh b/.test/tests/ipv6/run.sh new file mode 100755 index 000000000..0235db6b5 --- /dev/null +++ b/.test/tests/ipv6/run.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +[ "$DEBUG" ] && set -x + +set -eo pipefail + +# check if we have ipv6 available +if [ ! -f "/proc/net/if_inet6" ]; then + exit 0 +fi + +dir="$(dirname "$(readlink -f "$BASH_SOURCE")")" + +image="$1" + +clientImage='buildpack-deps:buster-curl' +# ensure the clientImage is ready and available +if ! docker image inspect "$clientImage" &> /dev/null; then + docker pull "$clientImage" > /dev/null +fi + +cid="$(docker run -d "$image")" +trap "docker rm -vf $cid > /dev/null" EXIT + +_request() { + local method="$1" + shift + + local proto="$1" + shift + + local url="${1#/}" + shift + + if [ "$(docker inspect -f '{{.State.Running}}' "$cid" 2>/dev/null)" != 'true' ]; then + echo >&2 "$image stopped unexpectedly!" + ( set -x && docker logs "$cid" ) >&2 || true + false + fi + + docker run --rm \ + --link "$cid":nginx \ + "$clientImage" \ + curl -fsSL -X"$method" --connect-to '::nginx:' "$@" "$proto://example.com/$url" +} + +. "$HOME/oi/test/retry.sh" '[ "$(_request GET / --output /dev/null || echo $?)" != 7 ]' + +# Check that we can request / +_request GET http '/index.html' | grep '

Welcome to nginx!

' + +docker logs $cid 2>&1 | grep "Enabled listen on IPv6" diff --git a/.test/tests/modules/nginx.conf.sme b/.test/tests/modules/nginx.conf.sme new file mode 100644 index 000000000..dab101456 --- /dev/null +++ b/.test/tests/modules/nginx.conf.sme @@ -0,0 +1,34 @@ +user nginx; +worker_processes auto; + +load_module modules/ndk_http_module.so; +load_module modules/ngx_http_echo_module.so; +load_module modules/ngx_http_set_misc_module.so; + +error_log /var/log/nginx/error.log notice; +pid /var/run/nginx.pid; + +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + server { + listen 80 default_server; + location /hello { + set $raw "hello"; + set_sha1 $digest $raw; + + echo $digest; + } + } +} diff --git a/.test/tests/modules/run.sh b/.test/tests/modules/run.sh new file mode 100755 index 000000000..257cdd551 --- /dev/null +++ b/.test/tests/modules/run.sh @@ -0,0 +1,71 @@ +#!/bin/bash + +set -eo pipefail + +dir="$(dirname "$(readlink -f "$BASH_SOURCE")")" + +echo $dir + +image="$1" + +case "$image" in + *-perl) + ;; + *) + echo >&2 "skipping non-leaf image: $image" + exit + ;; +esac + +dockerfile="Dockerfile" +case "$image" in + *alpine*) + dockerfile="$dockerfile.alpine" + ;; +esac + +clientImage='buildpack-deps:buster-curl' +# ensure the clientImage is ready and available +if ! docker image inspect "$clientImage" &> /dev/null; then + docker pull "$clientImage" > /dev/null +fi + +# Create an instance of the container-under-test +modulesImage="$("$HOME/oi/test/tests/image-name.sh" librarytest/nginx-template "$image")" +docker build --build-arg NGINX_FROM_IMAGE="$image" --build-arg ENABLED_MODULES="ndk set-misc echo" -t "$modulesImage" -f "modules/$dockerfile" "$GITHUB_WORKSPACE/modules" + +serverImage="${modulesImage}-sme" +"$HOME/oi/test/tests/docker-build.sh" "$dir" "$serverImage" < /dev/null" EXIT + +_request() { + local method="$1" + shift + + local proto="$1" + shift + + local url="${1#/}" + shift + + if [ "$(docker inspect -f '{{.State.Running}}' "$cid" 2>/dev/null)" != 'true' ]; then + echo >&2 "$image stopped unexpectedly!" + ( set -x && docker logs "$cid" ) >&2 || true + false + fi + + docker run --rm \ + --link "$cid":nginx \ + "$clientImage" \ + curl -fsSL -X"$method" --connect-to '::nginx:' "$@" "$proto://example.com/$url" +} + +. "$HOME/oi/test/retry.sh" '[ "$(_request GET / --output /dev/null || echo $?)" != 7 ]' + +# Check that we can request / +_request GET http '/hello' | grep 'aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d' diff --git a/.test/tests/static/run.sh b/.test/tests/static/run.sh new file mode 100755 index 000000000..f026bedb3 --- /dev/null +++ b/.test/tests/static/run.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +[ "$DEBUG" ] && set -x + +set -eo pipefail + +dir="$(dirname "$(readlink -f "$BASH_SOURCE")")" + +image="$1" + +clientImage='buildpack-deps:buster-curl' +# ensure the clientImage is ready and available +if ! docker image inspect "$clientImage" &> /dev/null; then + docker pull "$clientImage" > /dev/null +fi + +# Create an instance of the container-under-test +cid="$(docker run -d "$image")" +trap "docker rm -vf $cid > /dev/null" EXIT + +_request() { + local method="$1" + shift + + local proto="$1" + shift + + local url="${1#/}" + shift + + if [ "$(docker inspect -f '{{.State.Running}}' "$cid" 2>/dev/null)" != 'true' ]; then + echo >&2 "$image stopped unexpectedly!" + ( set -x && docker logs "$cid" ) >&2 || true + false + fi + + docker run --rm \ + --link "$cid":nginx \ + "$clientImage" \ + curl -fsSL -X"$method" --connect-to '::nginx:' "$@" "$proto://example.com/$url" +} + +. "$HOME/oi/test/retry.sh" '[ "$(_request GET / --output /dev/null || echo $?)" != 7 ]' + +# Check that we can request / +_request GET http '/index.html' | grep '

Welcome to nginx!

' diff --git a/.test/tests/templates-resolver-ipv6/expected-std-out.txt b/.test/tests/templates-resolver-ipv6/expected-std-out.txt new file mode 100644 index 000000000..38bfee851 --- /dev/null +++ b/.test/tests/templates-resolver-ipv6/expected-std-out.txt @@ -0,0 +1 @@ +example.com - OK diff --git a/.test/tests/templates-resolver-ipv6/run.sh b/.test/tests/templates-resolver-ipv6/run.sh new file mode 100755 index 000000000..88476d650 --- /dev/null +++ b/.test/tests/templates-resolver-ipv6/run.sh @@ -0,0 +1,70 @@ +#!/bin/bash + +[ "$DEBUG" ] && set -x + +set -eo pipefail + +# check if we have ipv6 available +if [ ! -f "/proc/net/if_inet6" ]; then + exit 0 +fi + +dir="$(dirname "$(readlink -f "$BASH_SOURCE")")" + +image="$1" + +clientImage='buildpack-deps:buster-curl' +# ensure the clientImage is ready and available +if ! docker image inspect "$clientImage" &> /dev/null; then + docker pull "$clientImage" > /dev/null +fi + +# Create a new Docker network +nid="$(docker network create --ipv6 --subnet fd0c:7e57::/64 nginx-test-ipv6-network)" + +_network_exit_handler() { + docker network rm -f $nid > /dev/null +} + +# Create an instance of the container-under-test +serverImage="$("$HOME/oi/test/tests/image-name.sh" librarytest/nginx-template "$image")" +"$HOME/oi/test/tests/docker-build.sh" "$dir" "$serverImage" < /dev/null +} +_exit_handler() { _container_exit_handler; _network_exit_handler; } +trap "_exit_handler" EXIT + +ipv6cid="$(docker inspect -f '{{range.NetworkSettings.Networks}}{{.GlobalIPv6Address}}{{end}}' $cid)" + +_request() { + local method="$1" + shift + + local proto="$1" + shift + + local url="${1#/}" + shift + + if [ "$(docker inspect -f '{{.State.Running}}' "$cid" 2>/dev/null)" != 'true' ]; then + echo >&2 "$image stopped unexpectedly!" + ( set -x && docker logs "$cid" ) >&2 || true + false + fi + + docker run --rm \ + --network "$nid" \ + "$clientImage" \ + curl -fsSL -X"$method" --connect-to "::[$ipv6cid]:" "$@" "$proto://example.com/$url" +} + +. "$HOME/oi/test/retry.sh" '[ "$(_request GET / --output /dev/null || echo $?)" != 7 ]' + +# Check that we can request / +_request GET http '/resolver-templates' | grep 'example.com - OK' diff --git a/.test/tests/templates-resolver-ipv6/server.conf.template b/.test/tests/templates-resolver-ipv6/server.conf.template new file mode 100644 index 000000000..70835560f --- /dev/null +++ b/.test/tests/templates-resolver-ipv6/server.conf.template @@ -0,0 +1,10 @@ +resolver ${NGINX_LOCAL_RESOLVERS}; + +server { + listen 80; + listen [::]:80; + server_name ${NGINX_MY_SERVER_NAME}; + default_type text/plain; + location = / { return 200 'OK\n'; } + location / { return 200 "${NGINX_MY_SERVER_NAME} - OK\n"; } +} diff --git a/.test/tests/templates-resolver/run.sh b/.test/tests/templates-resolver/run.sh new file mode 100755 index 000000000..041f7abd5 --- /dev/null +++ b/.test/tests/templates-resolver/run.sh @@ -0,0 +1,51 @@ +#!/bin/bash + +[ "$DEBUG" ] && set -x + +set -eo pipefail + +dir="$(dirname "$(readlink -f "$BASH_SOURCE")")" + +image="$1" + +clientImage='buildpack-deps:buster-curl' +# ensure the clientImage is ready and available +if ! docker image inspect "$clientImage" &> /dev/null; then + docker pull "$clientImage" > /dev/null +fi + +# Create an instance of the container-under-test +serverImage="$("$HOME/oi/test/tests/image-name.sh" librarytest/nginx-template "$image")" +"$HOME/oi/test/tests/docker-build.sh" "$dir" "$serverImage" < /dev/null" EXIT + +_request() { + local method="$1" + shift + + local proto="$1" + shift + + local url="${1#/}" + shift + + if [ "$(docker inspect -f '{{.State.Running}}' "$cid" 2>/dev/null)" != 'true' ]; then + echo >&2 "$image stopped unexpectedly!" + ( set -x && docker logs "$cid" ) >&2 || true + false + fi + + docker run --rm \ + --link "$cid":nginx \ + "$clientImage" \ + curl -fsSL -X"$method" --connect-to '::nginx:' "$@" "$proto://example.com/$url" +} + +. "$HOME/oi/test/retry.sh" '[ "$(_request GET / --output /dev/null || echo $?)" != 7 ]' + +# Check that we can request / +_request GET http '/resolver-templates' | grep 'example.com - OK' diff --git a/.test/tests/templates-resolver/server.conf.template b/.test/tests/templates-resolver/server.conf.template new file mode 100644 index 000000000..04a0c0859 --- /dev/null +++ b/.test/tests/templates-resolver/server.conf.template @@ -0,0 +1,9 @@ +resolver ${NGINX_LOCAL_RESOLVERS}; + +server { + listen 80; + server_name ${NGINX_MY_SERVER_NAME}; + default_type text/plain; + location = / { return 200 'OK\n'; } + location / { return 200 "${NGINX_MY_SERVER_NAME} - OK\n"; } +} diff --git a/.test/tests/templates/run.sh b/.test/tests/templates/run.sh new file mode 100755 index 000000000..c43aa1db0 --- /dev/null +++ b/.test/tests/templates/run.sh @@ -0,0 +1,51 @@ +#!/bin/bash + +[ "$DEBUG" ] && set -x + +set -eo pipefail + +dir="$(dirname "$(readlink -f "$BASH_SOURCE")")" + +image="$1" + +clientImage='buildpack-deps:buster-curl' +# ensure the clientImage is ready and available +if ! docker image inspect "$clientImage" &> /dev/null; then + docker pull "$clientImage" > /dev/null +fi + +# Create an instance of the container-under-test +serverImage="$("$HOME/oi/test/tests/image-name.sh" librarytest/nginx-template "$image")" +"$HOME/oi/test/tests/docker-build.sh" "$dir" "$serverImage" < /dev/null" EXIT + +_request() { + local method="$1" + shift + + local proto="$1" + shift + + local url="${1#/}" + shift + + if [ "$(docker inspect -f '{{.State.Running}}' "$cid" 2>/dev/null)" != 'true' ]; then + echo >&2 "$image stopped unexpectedly!" + ( set -x && docker logs "$cid" ) >&2 || true + false + fi + + docker run --rm \ + --link "$cid":nginx \ + "$clientImage" \ + curl -fsSL -X"$method" --connect-to '::nginx:' "$@" "$proto://example.com/$url" +} + +. "$HOME/oi/test/retry.sh" '[ "$(_request GET / --output /dev/null || echo $?)" != 7 ]' + +# Check that we can request / +_request GET http '/templates' | grep 'example.com - OK' diff --git a/.test/tests/templates/server.conf.template b/.test/tests/templates/server.conf.template new file mode 100644 index 000000000..6b00bed6c --- /dev/null +++ b/.test/tests/templates/server.conf.template @@ -0,0 +1,7 @@ +server { + listen 80; + server_name ${NGINX_MY_SERVER_NAME}; + default_type text/plain; + location = / { return 200 'OK\n'; } + location / { return 200 "${NGINX_MY_SERVER_NAME} - OK\n"; } +} diff --git a/.test/tests/workers/expected-std-out.txt b/.test/tests/workers/expected-std-out.txt new file mode 100644 index 000000000..9f1d3ac3a --- /dev/null +++ b/.test/tests/workers/expected-std-out.txt @@ -0,0 +1,2 @@ +example.com - OK +# Commented out by 30-tune-worker-processes.sh diff --git a/.test/tests/workers/run.sh b/.test/tests/workers/run.sh new file mode 100755 index 000000000..50def70cb --- /dev/null +++ b/.test/tests/workers/run.sh @@ -0,0 +1,55 @@ +#!/bin/bash + +[ "$DEBUG" ] && set -x + +set -eo pipefail + +dir="$(dirname "$(readlink -f "$BASH_SOURCE")")" + +image="$1" + +clientImage='buildpack-deps:buster-curl' +# ensure the clientImage is ready and available +if ! docker image inspect "$clientImage" &> /dev/null; then + docker pull "$clientImage" > /dev/null +fi + +# Create an instance of the container-under-test +serverImage="$("$HOME/oi/test/tests/image-name.sh" librarytest/nginx-template "$image")" +"$HOME/oi/test/tests/docker-build.sh" "$dir" "$serverImage" < /dev/null" EXIT + +_request() { + local method="$1" + shift + + local proto="$1" + shift + + local url="${1#/}" + shift + + if [ "$(docker inspect -f '{{.State.Running}}' "$cid" 2>/dev/null)" != 'true' ]; then + echo >&2 "$image stopped unexpectedly!" + ( set -x && docker logs "$cid" ) >&2 || true + false + fi + + docker run --rm \ + --link "$cid":nginx \ + "$clientImage" \ + curl -fsSL -X"$method" --connect-to '::nginx:' "$@" "$proto://example.com/$url" +} + +. "$HOME/oi/test/retry.sh" '[ "$(_request GET / --output /dev/null || echo $?)" != 7 ]' + +# Check that we can request / +_request GET http '/worker-templates' | grep 'example.com - OK' + +result="$(docker exec $cid grep "Commented out by" /etc/nginx/nginx.conf)" + +echo "$result" | cut -d\ -f 1-5 diff --git a/.test/tests/workers/server.conf.template b/.test/tests/workers/server.conf.template new file mode 100644 index 000000000..6b00bed6c --- /dev/null +++ b/.test/tests/workers/server.conf.template @@ -0,0 +1,7 @@ +server { + listen 80; + server_name ${NGINX_MY_SERVER_NAME}; + default_type text/plain; + location = / { return 200 'OK\n'; } + location / { return 200 "${NGINX_MY_SERVER_NAME} - OK\n"; } +} diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..e18d3706b --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,78 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our community include: + +- Demonstrating empathy and kindness toward other people. +- Being respectful of differing opinions, viewpoints, and experiences. +- Giving and gracefully accepting constructive feedback. +- Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience. +- Focusing on what is best not just for us as individuals, but for the overall community. + +Examples of unacceptable behavior include: + +- The use of sexualized language or imagery, and sexual attention or advances of any kind. +- Trolling, insulting or derogatory comments, and personal or political attacks. +- Public or private harassment. +- Publishing others' private information, such as a physical or email address, without their explicit permission. +- Other conduct which could reasonably be considered inappropriate in a professional setting. + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official email address, posting via an official social media account, or acting as an appointed representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at . All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of actions. + +**Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 2.1, available at . + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/inclusion). + +For answers to common questions about this code of conduct, see the FAQ at . Translations are available at . diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..ebdcace7c --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,56 @@ +# Contributing Guidelines + +The following is a set of guidelines for contributing to the Docker NGINX image. We really appreciate that you are considering contributing! + +#### Table Of Contents + +- [Getting Started](#getting-started) +- [Contributing](#contributing) +- [Code Guidelines](#code-guidelines) +- [Code of Conduct](/CODE_OF_CONDUCT.md) + +## Getting Started + +Follow our [how to use this image guide](https://hub.docker.com/_/nginx/) to get the Docker NGINX image up and running. + +## Contributing + +### Report a Bug + +To report a bug, open an issue on GitHub with the label `bug` using the available [bug report issue form](/.github/ISSUE_TEMPLATE/bug_report.yml). Please ensure the bug has not already been reported. **If the bug is a potential security vulnerability, please report it using our [security policy](/SECURITY.md).** + +### Suggest a Feature or Enhancement + +To suggest a feature or enhancement, please create an issue on GitHub with the label `enhancement` using the available [feature request issue form](/.github/ISSUE_TEMPLATE/feature_request.yml). Please ensure the feature or enhancement has not already been suggested. + +### Open a Pull Request (PR) + +- Fork the repo, create a branch, implement your changes, add any relevant tests, and submit a PR when your changes are **tested** and ready for review. +- Fill in the [PR template](/.github/pull_request_template.md). + +**Note:** If you'd like to implement a new feature, please consider creating a [feature request issue](/.github/ISSUE_TEMPLATE/feature_request.yml) first to start a discussion about the feature. + +#### F5 Contributor License Agreement (CLA) + +F5 requires all contributors to agree to the terms of the F5 CLA (available [here](https://github.com/f5/f5-cla/.github/blob/main/docs/f5_cla.md)) before any of their changes can be incorporated into an F5 Open Source repository (even contributions to the F5 CLA itself!). + +If you have not yet agreed to the F5 CLA terms and submit a PR to this repository, a bot will prompt you to view and agree to the F5 CLA. You will have to agree to the F5 CLA terms through a comment in the PR before any of your changes can be merged. Your agreement signature will be safely stored by F5 and no longer be required in future PRs. + +## Code Guidelines + +### Git Guidelines + +- Keep a clean, concise and meaningful git commit history on your branch (within reason), rebasing locally and squashing before submitting a PR. +- If possible and/or relevant, use the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) format when writing a commit message, so that changelogs can be automatically generated +- Follow the guidelines of writing a good commit message as described here and summarised in the next few points: + - In the subject line, use the present tense ("Add feature" not "Added feature"). + - In the subject line, use the imperative mood ("Move cursor to..." not "Moves cursor to..."). + - Limit the subject line to 72 characters or less. + - Reference issues and pull requests liberally after the subject line. + - Add more detailed description in the body of the git message (`git commit -a` to give you more space and time in your text editor to write a good message instead of `git commit -am`). + +### Docker Guidelines + +- Update any entrypoint scripts via the the scripts contained in the `/entrypoint` directory. +- Update any Dockerfiles via the Dockerfile templates in the root directory (e.g. `Dockerfile-alpine.template`). +- Run the `./update.sh` script to apply all entrypoint/Dockerfile template changes to the relevant image entrypoints & Dockerfiles. diff --git a/Dockerfile-alpine-otel.template b/Dockerfile-alpine-otel.template new file mode 100644 index 000000000..b870b9544 --- /dev/null +++ b/Dockerfile-alpine-otel.template @@ -0,0 +1,66 @@ +FROM nginx:%%NGINX_VERSION%%-alpine + +ENV OTEL_VERSION %%OTEL_VERSION%% + +RUN set -x \ + && apkArch="$(cat /etc/apk/arch)" \ + && nginxPackages="%%PACKAGES%% + " \ +# install prerequisites for public key and pkg-oss checks + && apk add --no-cache --virtual .checksum-deps \ + openssl \ + && case "$apkArch" in \ + x86_64|aarch64) \ +# arches officially built by upstream + apk add -X "%%PACKAGEREPO%%v$(egrep -o '^[0-9]+\.[0-9]+' /etc/alpine-release)/main" --no-cache $nginxPackages \ + ;; \ + *) \ +# we're on an architecture upstream doesn't officially build for +# let's build binaries from the published packaging sources + set -x \ + && tempDir="$(mktemp -d)" \ + && chown nobody:nobody $tempDir \ + && apk add --no-cache --virtual .build-deps \ + gcc \ + libc-dev \ + make \ + openssl-dev \ + pcre2-dev \ + zlib-dev \ + linux-headers \ + cmake \ + bash \ + alpine-sdk \ + findutils \ + curl \ + xz \ + protobuf-dev \ + grpc-dev \ + && su nobody -s /bin/sh -c " \ + export HOME=${tempDir} \ + && cd ${tempDir} \ + && curl -f -L -O https://github.com/nginx/pkg-oss/archive/%%REVISION%%.tar.gz \ + && PKGOSSCHECKSUM=\"%%PKGOSSCHECKSUM%% *%%REVISION%%.tar.gz\" \ + && if [ \"\$(openssl sha512 -r %%REVISION%%.tar.gz)\" = \"\$PKGOSSCHECKSUM\" ]; then \ + echo \"pkg-oss tarball checksum verification succeeded!\"; \ + else \ + echo \"pkg-oss tarball checksum verification failed!\"; \ + exit 1; \ + fi \ + && tar xzvf %%REVISION%%.tar.gz \ + && cd pkg-oss-%%REVISION%% \ + && cd alpine \ + && make %%BUILDTARGET%% \ + && apk index --allow-untrusted -o ${tempDir}/packages/alpine/${apkArch}/APKINDEX.tar.gz ${tempDir}/packages/alpine/${apkArch}/*.apk \ + && abuild-sign -k ${tempDir}/.abuild/abuild-key.rsa ${tempDir}/packages/alpine/${apkArch}/APKINDEX.tar.gz \ + " \ + && cp ${tempDir}/.abuild/abuild-key.rsa.pub /etc/apk/keys/ \ + && apk del --no-network .build-deps \ + && apk add -X ${tempDir}/packages/alpine/ --no-cache $nginxPackages \ + ;; \ + esac \ +# remove checksum deps + && apk del --no-network .checksum-deps \ +# if we have leftovers from building, let's purge them (including extra, unnecessary build deps) + && if [ -n "$tempDir" ]; then rm -rf "$tempDir"; fi \ + && if [ -f "/etc/apk/keys/abuild-key.rsa.pub" ]; then rm -f /etc/apk/keys/abuild-key.rsa.pub; fi diff --git a/Dockerfile-alpine-perl.template b/Dockerfile-alpine-perl.template new file mode 100644 index 000000000..6fc37deac --- /dev/null +++ b/Dockerfile-alpine-perl.template @@ -0,0 +1,61 @@ +FROM nginx:%%NGINX_VERSION%%-alpine + +RUN set -x \ + && apkArch="$(cat /etc/apk/arch)" \ + && nginxPackages="%%PACKAGES%% + " \ +# install prerequisites for public key and pkg-oss checks + && apk add --no-cache --virtual .checksum-deps \ + openssl \ + && case "$apkArch" in \ + x86_64|aarch64) \ +# arches officially built by upstream + apk add -X "%%PACKAGEREPO%%v$(egrep -o '^[0-9]+\.[0-9]+' /etc/alpine-release)/main" --no-cache $nginxPackages \ + ;; \ + *) \ +# we're on an architecture upstream doesn't officially build for +# let's build binaries from the published packaging sources + set -x \ + && tempDir="$(mktemp -d)" \ + && chown nobody:nobody $tempDir \ + && apk add --no-cache --virtual .build-deps \ + gcc \ + libc-dev \ + make \ + openssl-dev \ + pcre2-dev \ + zlib-dev \ + linux-headers \ + perl-dev \ + bash \ + alpine-sdk \ + findutils \ + curl \ + && su nobody -s /bin/sh -c " \ + export HOME=${tempDir} \ + && cd ${tempDir} \ + && curl -f -L -O https://github.com/nginx/pkg-oss/archive/%%REVISION%%.tar.gz \ + && PKGOSSCHECKSUM=\"%%PKGOSSCHECKSUM%% *%%REVISION%%.tar.gz\" \ + && if [ \"\$(openssl sha512 -r %%REVISION%%.tar.gz)\" = \"\$PKGOSSCHECKSUM\" ]; then \ + echo \"pkg-oss tarball checksum verification succeeded!\"; \ + else \ + echo \"pkg-oss tarball checksum verification failed!\"; \ + exit 1; \ + fi \ + && tar xzvf %%REVISION%%.tar.gz \ + && cd pkg-oss-%%REVISION%% \ + && cd alpine \ + && make %%BUILDTARGET%% \ + && apk index --allow-untrusted -o ${tempDir}/packages/alpine/${apkArch}/APKINDEX.tar.gz ${tempDir}/packages/alpine/${apkArch}/*.apk \ + && abuild-sign -k ${tempDir}/.abuild/abuild-key.rsa ${tempDir}/packages/alpine/${apkArch}/APKINDEX.tar.gz \ + " \ + && cp ${tempDir}/.abuild/abuild-key.rsa.pub /etc/apk/keys/ \ + && apk del --no-network .build-deps \ + && apk add -X ${tempDir}/packages/alpine/ --no-cache $nginxPackages \ + ;; \ + esac \ +# remove checksum deps + && apk del --no-network .checksum-deps \ +# if we have leftovers from building, let's purge them (including extra, unnecessary build deps) + && if [ -n "$tempDir" ]; then rm -rf "$tempDir"; fi \ + && if [ -f "/etc/apk/keys/abuild-key.rsa.pub" ]; then rm -f /etc/apk/keys/abuild-key.rsa.pub; fi diff --git a/Dockerfile-alpine-slim.template b/Dockerfile-alpine-slim.template new file mode 100644 index 000000000..ff076f09c --- /dev/null +++ b/Dockerfile-alpine-slim.template @@ -0,0 +1,102 @@ +FROM alpine:%%ALPINE_VERSION%% + +LABEL maintainer="NGINX Docker Maintainers " + +ENV NGINX_VERSION %%NGINX_VERSION%% +ENV PKG_RELEASE %%PKG_RELEASE%% +ENV DYNPKG_RELEASE %%DYNPKG_RELEASE%% + +RUN set -x \ +# create nginx user/group first, to be consistent throughout docker variants + && addgroup -g 101 -S nginx \ + && adduser -S -D -H -u 101 -h /var/cache/nginx -s /sbin/nologin -G nginx -g nginx nginx \ + && apkArch="$(cat /etc/apk/arch)" \ + && nginxPackages="%%PACKAGES%% + " \ +# install prerequisites for public key and pkg-oss checks + && apk add --no-cache --virtual .checksum-deps \ + openssl \ + && case "$apkArch" in \ + x86_64|aarch64) \ +# arches officially built by upstream + set -x \ + && KEY_SHA512="e09fa32f0a0eab2b879ccbbc4d0e4fb9751486eedda75e35fac65802cc9faa266425edf83e261137a2f4d16281ce2c1a5f4502930fe75154723da014214f0655" \ + && wget -O /tmp/nginx_signing.rsa.pub https://nginx.org/keys/nginx_signing.rsa.pub \ + && if echo "$KEY_SHA512 */tmp/nginx_signing.rsa.pub" | sha512sum -c -; then \ + echo "key verification succeeded!"; \ + mv /tmp/nginx_signing.rsa.pub /etc/apk/keys/; \ + else \ + echo "key verification failed!"; \ + exit 1; \ + fi \ + && apk add -X "%%PACKAGEREPO%%v$(egrep -o '^[0-9]+\.[0-9]+' /etc/alpine-release)/main" --no-cache $nginxPackages \ + ;; \ + *) \ +# we're on an architecture upstream doesn't officially build for +# let's build binaries from the published packaging sources + set -x \ + && tempDir="$(mktemp -d)" \ + && chown nobody:nobody $tempDir \ + && apk add --no-cache --virtual .build-deps \ + gcc \ + libc-dev \ + make \ + openssl-dev \ + pcre2-dev \ + zlib-dev \ + linux-headers \ + bash \ + alpine-sdk \ + findutils \ + curl \ + && su nobody -s /bin/sh -c " \ + export HOME=${tempDir} \ + && cd ${tempDir} \ + && curl -f -L -O https://github.com/nginx/pkg-oss/archive/%%REVISION%%.tar.gz \ + && PKGOSSCHECKSUM=\"%%PKGOSSCHECKSUM%% *%%REVISION%%.tar.gz\" \ + && if [ \"\$(openssl sha512 -r %%REVISION%%.tar.gz)\" = \"\$PKGOSSCHECKSUM\" ]; then \ + echo \"pkg-oss tarball checksum verification succeeded!\"; \ + else \ + echo \"pkg-oss tarball checksum verification failed!\"; \ + exit 1; \ + fi \ + && tar xzvf %%REVISION%%.tar.gz \ + && cd pkg-oss-%%REVISION%% \ + && cd alpine \ + && make %%BUILDTARGET%% \ + && apk index --allow-untrusted -o ${tempDir}/packages/alpine/${apkArch}/APKINDEX.tar.gz ${tempDir}/packages/alpine/${apkArch}/*.apk \ + && abuild-sign -k ${tempDir}/.abuild/abuild-key.rsa ${tempDir}/packages/alpine/${apkArch}/APKINDEX.tar.gz \ + " \ + && cp ${tempDir}/.abuild/abuild-key.rsa.pub /etc/apk/keys/ \ + && apk del --no-network .build-deps \ + && apk add -X ${tempDir}/packages/alpine/ --no-cache $nginxPackages \ + ;; \ + esac \ +# remove checksum deps + && apk del --no-network .checksum-deps \ +# if we have leftovers from building, let's purge them (including extra, unnecessary build deps) + && if [ -n "$tempDir" ]; then rm -rf "$tempDir"; fi \ + && if [ -f "/etc/apk/keys/abuild-key.rsa.pub" ]; then rm -f /etc/apk/keys/abuild-key.rsa.pub; fi \ +# Add `envsubst` for templating environment variables + && apk add --no-cache gettext-envsubst \ +# Bring in tzdata so users could set the timezones through the environment +# variables + && apk add --no-cache tzdata \ +# forward request and error logs to docker log collector + && ln -sf /dev/stdout /var/log/nginx/access.log \ + && ln -sf /dev/stderr /var/log/nginx/error.log \ +# create a docker-entrypoint.d directory + && mkdir /docker-entrypoint.d + +COPY docker-entrypoint.sh / +COPY 10-listen-on-ipv6-by-default.sh /docker-entrypoint.d +COPY 15-local-resolvers.envsh /docker-entrypoint.d +COPY 20-envsubst-on-templates.sh /docker-entrypoint.d +COPY 30-tune-worker-processes.sh /docker-entrypoint.d +ENTRYPOINT ["/docker-entrypoint.sh"] + +EXPOSE 80 + +STOPSIGNAL SIGQUIT + +CMD ["nginx", "-g", "daemon off;"] diff --git a/Dockerfile-alpine.template b/Dockerfile-alpine.template index 909323d83..bc77dfd61 100644 --- a/Dockerfile-alpine.template +++ b/Dockerfile-alpine.template @@ -1,15 +1,9 @@ -FROM alpine:%%ALPINE_VERSION%% +FROM nginx:%%NGINX_VERSION%%-alpine-slim -LABEL maintainer="NGINX Docker Maintainers " - -ENV NGINX_VERSION %%NGINX_VERSION%% ENV NJS_VERSION %%NJS_VERSION%% -ENV PKG_RELEASE %%PKG_RELEASE%% +ENV NJS_RELEASE %%NJS_RELEASE%% RUN set -x \ -# create nginx user/group first, to be consistent throughout docker variants - && addgroup -g 101 -S nginx \ - && adduser -S -D -H -u 101 -h /var/cache/nginx -s /sbin/nologin -G nginx -g nginx nginx \ && apkArch="$(cat /etc/apk/arch)" \ && nginxPackages="%%PACKAGES%% " \ @@ -19,17 +13,7 @@ RUN set -x \ && case "$apkArch" in \ x86_64|aarch64) \ # arches officially built by upstream - set -x \ - && KEY_SHA512="e7fa8303923d9b95db37a77ad46c68fd4755ff935d0a534d26eba83de193c76166c68bfe7f65471bf8881004ef4aa6df3e34689c305662750c0172fca5d8552a *stdin" \ - && wget -O /tmp/nginx_signing.rsa.pub https://nginx.org/keys/nginx_signing.rsa.pub \ - && if [ "$(openssl rsa -pubin -in /tmp/nginx_signing.rsa.pub -text -noout | openssl sha512 -r)" = "$KEY_SHA512" ]; then \ - echo "key verification succeeded!"; \ - mv /tmp/nginx_signing.rsa.pub /etc/apk/keys/; \ - else \ - echo "key verification failed!"; \ - exit 1; \ - fi \ - && apk add -X "%%PACKAGEREPO%%v$(egrep -o '^[0-9]+\.[0-9]+' /etc/alpine-release)/main" --no-cache $nginxPackages \ + apk add -X "%%PACKAGEREPO%%v$(egrep -o '^[0-9]+\.[0-9]+' /etc/alpine-release)/main" --no-cache $nginxPackages \ ;; \ *) \ # we're on an architecture upstream doesn't officially build for @@ -48,15 +32,15 @@ RUN set -x \ libxslt-dev \ gd-dev \ geoip-dev \ - perl-dev \ libedit-dev \ bash \ alpine-sdk \ findutils \ + curl \ && su nobody -s /bin/sh -c " \ export HOME=${tempDir} \ && cd ${tempDir} \ - && curl -f -O https://hg.nginx.org/pkg-oss/archive/%%REVISION%%.tar.gz \ + && curl -f -L -O https://github.com/nginx/pkg-oss/archive/%%REVISION%%.tar.gz \ && PKGOSSCHECKSUM=\"%%PKGOSSCHECKSUM%% *%%REVISION%%.tar.gz\" \ && if [ \"\$(openssl sha512 -r %%REVISION%%.tar.gz)\" = \"\$PKGOSSCHECKSUM\" ]; then \ echo \"pkg-oss tarball checksum verification succeeded!\"; \ @@ -67,57 +51,19 @@ RUN set -x \ && tar xzvf %%REVISION%%.tar.gz \ && cd pkg-oss-%%REVISION%% \ && cd alpine \ - && make all \ - && apk index -o ${tempDir}/packages/alpine/${apkArch}/APKINDEX.tar.gz ${tempDir}/packages/alpine/${apkArch}/*.apk \ + && make %%BUILDTARGET%% \ + && apk index --allow-untrusted -o ${tempDir}/packages/alpine/${apkArch}/APKINDEX.tar.gz ${tempDir}/packages/alpine/${apkArch}/*.apk \ && abuild-sign -k ${tempDir}/.abuild/abuild-key.rsa ${tempDir}/packages/alpine/${apkArch}/APKINDEX.tar.gz \ " \ && cp ${tempDir}/.abuild/abuild-key.rsa.pub /etc/apk/keys/ \ - && apk del .build-deps \ + && apk del --no-network .build-deps \ && apk add -X ${tempDir}/packages/alpine/ --no-cache $nginxPackages \ ;; \ esac \ # remove checksum deps - && apk del .checksum-deps \ + && apk del --no-network .checksum-deps \ # if we have leftovers from building, let's purge them (including extra, unnecessary build deps) && if [ -n "$tempDir" ]; then rm -rf "$tempDir"; fi \ - && if [ -n "/etc/apk/keys/abuild-key.rsa.pub" ]; then rm -f /etc/apk/keys/abuild-key.rsa.pub; fi \ - && if [ -n "/etc/apk/keys/nginx_signing.rsa.pub" ]; then rm -f /etc/apk/keys/nginx_signing.rsa.pub; fi \ -# Bring in gettext so we can get `envsubst`, then throw -# the rest away. To do this, we need to install `gettext` -# then move `envsubst` out of the way so `gettext` can -# be deleted completely, then move `envsubst` back. - && apk add --no-cache --virtual .gettext gettext \ - && mv /usr/bin/envsubst /tmp/ \ - \ - && runDeps="$( \ - scanelf --needed --nobanner /tmp/envsubst \ - | awk '{ gsub(/,/, "\nso:", $2); print "so:" $2 }' \ - | sort -u \ - | xargs -r apk info --installed \ - | sort -u \ - )" \ - && apk add --no-cache $runDeps \ - && apk del .gettext \ - && mv /tmp/envsubst /usr/local/bin/ \ -# Bring in tzdata so users could set the timezones through the environment -# variables - && apk add --no-cache tzdata \ + && if [ -f "/etc/apk/keys/abuild-key.rsa.pub" ]; then rm -f /etc/apk/keys/abuild-key.rsa.pub; fi \ # Bring in curl and ca-certificates to make registering on DNS SD easier - && apk add --no-cache curl ca-certificates \ -# forward request and error logs to docker log collector - && ln -sf /dev/stdout /var/log/nginx/access.log \ - && ln -sf /dev/stderr /var/log/nginx/error.log \ -# create a docker-entrypoint.d directory - && mkdir /docker-entrypoint.d - -COPY docker-entrypoint.sh / -COPY 10-listen-on-ipv6-by-default.sh /docker-entrypoint.d -COPY 20-envsubst-on-templates.sh /docker-entrypoint.d -COPY 30-tune-worker-processes.sh /docker-entrypoint.d -ENTRYPOINT ["/docker-entrypoint.sh"] - -EXPOSE 80 - -STOPSIGNAL SIGQUIT - -CMD ["nginx", "-g", "daemon off;"] + && apk add --no-cache curl ca-certificates diff --git a/Dockerfile-debian-otel.template b/Dockerfile-debian-otel.template new file mode 100644 index 000000000..709836c17 --- /dev/null +++ b/Dockerfile-debian-otel.template @@ -0,0 +1,89 @@ +FROM nginx:%%NGINX_VERSION%% + +ENV OTEL_VERSION %%OTEL_VERSION%% + +RUN set -x; \ + NGINX_GPGKEY_PATH=/etc/apt/keyrings/nginx-archive-keyring.gpg; \ + dpkgArch="$(dpkg --print-architecture)" \ + && nginxPackages="%%PACKAGES%% + " \ + && case "$dpkgArch" in \ + amd64|arm64) \ +# arches officialy built by upstream + echo "deb [signed-by=$NGINX_GPGKEY_PATH] %%PACKAGEREPO%% %%DEBIAN_VERSION%% nginx" >> /etc/apt/sources.list.d/nginx.list \ + && apt-get update \ + ;; \ + *) \ +# we're on an architecture upstream doesn't officially build for +# let's build binaries from the published packaging sources +# new directory for storing sources and .deb files + tempDir="$(mktemp -d)" \ + && chmod 777 "$tempDir" \ +# (777 to ensure APT's "_apt" user can access it too) + \ +# save list of currently-installed packages so build dependencies can be cleanly removed later + && savedAptMark="$(apt-mark showmanual)" \ + \ +# build .deb files from upstream's packaging sources + && apt-get update \ + && apt-get install --no-install-recommends --no-install-suggests -y \ + curl \ + devscripts \ + equivs \ + git \ + libxml2-utils \ + lsb-release \ + xsltproc \ + && ( \ + cd "$tempDir" \ + && REVISION="%%REVISION%%" \ + && REVISION=${REVISION%~*} \ + && curl -f -L -O https://github.com/nginx/pkg-oss/archive/${REVISION}.tar.gz \ + && PKGOSSCHECKSUM="%%PKGOSSCHECKSUM%% *${REVISION}.tar.gz" \ + && if [ "$(openssl sha512 -r ${REVISION}.tar.gz)" = "$PKGOSSCHECKSUM" ]; then \ + echo "pkg-oss tarball checksum verification succeeded!"; \ + else \ + echo "pkg-oss tarball checksum verification failed!"; \ + exit 1; \ + fi \ + && tar xzvf ${REVISION}.tar.gz \ + && cd pkg-oss-${REVISION} \ + && cd debian \ + && for target in %%BUILDTARGET%%; do \ + make rules-$target; \ + mk-build-deps --install --tool="apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends --yes" \ + debuild-$target/nginx-$NGINX_VERSION/debian/control; \ + done \ + && make %%BUILDTARGET%% \ + ) \ +# we don't remove APT lists here because they get re-downloaded and removed later + \ +# reset apt-mark's "manual" list so that "purge --auto-remove" will remove all build dependencies +# (which is done after we install the built packages so we don't have to redownload any overlapping dependencies) + && apt-mark showmanual | xargs apt-mark auto > /dev/null \ + && { [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; } \ + \ +# create a temporary local APT repo to install from (so that dependency resolution can be handled by APT, as it should be) + && ls -lAFh "$tempDir" \ + && ( cd "$tempDir" && dpkg-scanpackages . > Packages ) \ + && grep '^Package: ' "$tempDir/Packages" \ + && echo "deb [ trusted=yes ] file://$tempDir ./" > /etc/apt/sources.list.d/temp.list \ +# work around the following APT issue by using "Acquire::GzipIndexes=false" (overriding "/etc/apt/apt.conf.d/docker-gzip-indexes") +# Could not open file /var/lib/apt/lists/partial/_tmp_tmp.ODWljpQfkE_._Packages - open (13: Permission denied) +# ... +# E: Failed to fetch store:/var/lib/apt/lists/partial/_tmp_tmp.ODWljpQfkE_._Packages Could not open file /var/lib/apt/lists/partial/_tmp_tmp.ODWljpQfkE_._Packages - open (13: Permission denied) + && apt-get -o Acquire::GzipIndexes=false update \ + ;; \ + esac \ + \ + && apt-get install --no-install-recommends --no-install-suggests -y \ + $nginxPackages \ + gettext-base \ + curl \ + && apt-get remove --purge --auto-remove -y && rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/nginx.list \ + \ +# if we have leftovers from building, let's purge them (including extra, unnecessary build deps) + && if [ -n "$tempDir" ]; then \ + apt-get purge -y --auto-remove \ + && rm -rf "$tempDir" /etc/apt/sources.list.d/temp.list; \ + fi diff --git a/Dockerfile-debian-perl.template b/Dockerfile-debian-perl.template new file mode 100644 index 000000000..84cf99f6e --- /dev/null +++ b/Dockerfile-debian-perl.template @@ -0,0 +1,87 @@ +FROM nginx:%%NGINX_VERSION%% + +RUN set -x; \ + NGINX_GPGKEY_PATH=/etc/apt/keyrings/nginx-archive-keyring.gpg; \ + dpkgArch="$(dpkg --print-architecture)" \ + && nginxPackages="%%PACKAGES%% + " \ + && case "$dpkgArch" in \ + amd64|arm64) \ +# arches officialy built by upstream + echo "deb [signed-by=$NGINX_GPGKEY_PATH] %%PACKAGEREPO%% %%DEBIAN_VERSION%% nginx" >> /etc/apt/sources.list.d/nginx.list \ + && apt-get update \ + ;; \ + *) \ +# we're on an architecture upstream doesn't officially build for +# let's build binaries from the published packaging sources +# new directory for storing sources and .deb files + tempDir="$(mktemp -d)" \ + && chmod 777 "$tempDir" \ +# (777 to ensure APT's "_apt" user can access it too) + \ +# save list of currently-installed packages so build dependencies can be cleanly removed later + && savedAptMark="$(apt-mark showmanual)" \ + \ +# build .deb files from upstream's packaging sources + && apt-get update \ + && apt-get install --no-install-recommends --no-install-suggests -y \ + curl \ + devscripts \ + equivs \ + git \ + libxml2-utils \ + lsb-release \ + xsltproc \ + && ( \ + cd "$tempDir" \ + && REVISION="%%REVISION%%" \ + && REVISION=${REVISION%~*} \ + && curl -f -L -O https://github.com/nginx/pkg-oss/archive/${REVISION}.tar.gz \ + && PKGOSSCHECKSUM="%%PKGOSSCHECKSUM%% *${REVISION}.tar.gz" \ + && if [ "$(openssl sha512 -r ${REVISION}.tar.gz)" = "$PKGOSSCHECKSUM" ]; then \ + echo "pkg-oss tarball checksum verification succeeded!"; \ + else \ + echo "pkg-oss tarball checksum verification failed!"; \ + exit 1; \ + fi \ + && tar xzvf ${REVISION}.tar.gz \ + && cd pkg-oss-${REVISION} \ + && cd debian \ + && for target in %%BUILDTARGET%%; do \ + make rules-$target; \ + mk-build-deps --install --tool="apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends --yes" \ + debuild-$target/nginx-$NGINX_VERSION/debian/control; \ + done \ + && make %%BUILDTARGET%% \ + ) \ +# we don't remove APT lists here because they get re-downloaded and removed later + \ +# reset apt-mark's "manual" list so that "purge --auto-remove" will remove all build dependencies +# (which is done after we install the built packages so we don't have to redownload any overlapping dependencies) + && apt-mark showmanual | xargs apt-mark auto > /dev/null \ + && { [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; } \ + \ +# create a temporary local APT repo to install from (so that dependency resolution can be handled by APT, as it should be) + && ls -lAFh "$tempDir" \ + && ( cd "$tempDir" && dpkg-scanpackages . > Packages ) \ + && grep '^Package: ' "$tempDir/Packages" \ + && echo "deb [ trusted=yes ] file://$tempDir ./" > /etc/apt/sources.list.d/temp.list \ +# work around the following APT issue by using "Acquire::GzipIndexes=false" (overriding "/etc/apt/apt.conf.d/docker-gzip-indexes") +# Could not open file /var/lib/apt/lists/partial/_tmp_tmp.ODWljpQfkE_._Packages - open (13: Permission denied) +# ... +# E: Failed to fetch store:/var/lib/apt/lists/partial/_tmp_tmp.ODWljpQfkE_._Packages Could not open file /var/lib/apt/lists/partial/_tmp_tmp.ODWljpQfkE_._Packages - open (13: Permission denied) + && apt-get -o Acquire::GzipIndexes=false update \ + ;; \ + esac \ + \ + && apt-get install --no-install-recommends --no-install-suggests -y \ + $nginxPackages \ + gettext-base \ + curl \ + && apt-get remove --purge --auto-remove -y && rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/nginx.list \ + \ +# if we have leftovers from building, let's purge them (including extra, unnecessary build deps) + && if [ -n "$tempDir" ]; then \ + apt-get purge -y --auto-remove \ + && rm -rf "$tempDir" /etc/apt/sources.list.d/temp.list; \ + fi diff --git a/Dockerfile-debian.template b/Dockerfile-debian.template index 8c7bf16f5..57abba1ab 100644 --- a/Dockerfile-debian.template +++ b/Dockerfile-debian.template @@ -4,25 +4,33 @@ LABEL maintainer="NGINX Docker Maintainers " ENV NGINX_VERSION %%NGINX_VERSION%% ENV NJS_VERSION %%NJS_VERSION%% +ENV NJS_RELEASE %%NJS_RELEASE%% ENV PKG_RELEASE %%PKG_RELEASE%% +ENV DYNPKG_RELEASE %%DYNPKG_RELEASE%% RUN set -x \ # create nginx user/group first, to be consistent throughout docker variants - && addgroup --system --gid 101 nginx \ - && adduser --system --disabled-login --ingroup nginx --no-create-home --home /nonexistent --gecos "nginx user" --shell /bin/false --uid 101 nginx \ + && groupadd --system --gid 101 nginx \ + && useradd --system --gid nginx --no-create-home --home /nonexistent --comment "nginx user" --shell /bin/false --uid 101 nginx \ && apt-get update \ && apt-get install --no-install-recommends --no-install-suggests -y gnupg1 ca-certificates \ && \ - NGINX_GPGKEY=573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62; \ + NGINX_GPGKEYS="573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 8540A6F18833A80E9C1653A42FD21310B49F6B46 9E9BE90EACBCDE69FE9B204CBCDCD8A38D88A2B3"; \ + NGINX_GPGKEY_PATH=/etc/apt/keyrings/nginx-archive-keyring.gpg; \ + export GNUPGHOME="$(mktemp -d)"; \ found=''; \ + for NGINX_GPGKEY in $NGINX_GPGKEYS; do \ for server in \ hkp://keyserver.ubuntu.com:80 \ pgp.mit.edu \ ; do \ echo "Fetching GPG key $NGINX_GPGKEY from $server"; \ - apt-key adv --keyserver "$server" --keyserver-options timeout=10 --recv-keys "$NGINX_GPGKEY" && found=yes && break; \ + gpg1 --batch --keyserver "$server" --keyserver-options timeout=10 --recv-keys "$NGINX_GPGKEY" && found=yes && break; \ done; \ test -z "$found" && echo >&2 "error: failed to fetch GPG key $NGINX_GPGKEY" && exit 1; \ + done; \ + gpg1 --batch --export $NGINX_GPGKEYS > "$NGINX_GPGKEY_PATH" ; \ + rm -rf "$GNUPGHOME"; \ apt-get remove --purge --auto-remove -y gnupg1 && rm -rf /var/lib/apt/lists/* \ && dpkgArch="$(dpkg --print-architecture)" \ && nginxPackages="%%PACKAGES%% @@ -30,29 +38,51 @@ RUN set -x \ && case "$dpkgArch" in \ amd64|arm64) \ # arches officialy built by upstream - echo "deb %%PACKAGEREPO%% %%DEBIAN_VERSION%% nginx" >> /etc/apt/sources.list.d/nginx.list \ + echo "deb [signed-by=$NGINX_GPGKEY_PATH] %%PACKAGEREPO%% %%DEBIAN_VERSION%% nginx" >> /etc/apt/sources.list.d/nginx.list \ && apt-get update \ ;; \ *) \ # we're on an architecture upstream doesn't officially build for -# let's build binaries from the published source packages - echo "deb-src %%PACKAGEREPO%% %%DEBIAN_VERSION%% nginx" >> /etc/apt/sources.list.d/nginx.list \ - \ +# let's build binaries from the published packaging sources # new directory for storing sources and .deb files - && tempDir="$(mktemp -d)" \ + tempDir="$(mktemp -d)" \ && chmod 777 "$tempDir" \ # (777 to ensure APT's "_apt" user can access it too) \ # save list of currently-installed packages so build dependencies can be cleanly removed later && savedAptMark="$(apt-mark showmanual)" \ \ -# build .deb files from upstream's source packages (which are verified by apt-get) +# build .deb files from upstream's packaging sources && apt-get update \ - && apt-get build-dep -y $nginxPackages \ + && apt-get install --no-install-recommends --no-install-suggests -y \ + curl \ + devscripts \ + equivs \ + git \ + libxml2-utils \ + lsb-release \ + xsltproc \ && ( \ cd "$tempDir" \ - && DEB_BUILD_OPTIONS="nocheck parallel=$(nproc)" \ - apt-get source --compile $nginxPackages \ + && REVISION="%%REVISION%%" \ + && REVISION=${REVISION%~*} \ + && curl -f -L -O https://github.com/nginx/pkg-oss/archive/${REVISION}.tar.gz \ + && PKGOSSCHECKSUM="%%PKGOSSCHECKSUM%% *${REVISION}.tar.gz" \ + && if [ "$(openssl sha512 -r ${REVISION}.tar.gz)" = "$PKGOSSCHECKSUM" ]; then \ + echo "pkg-oss tarball checksum verification succeeded!"; \ + else \ + echo "pkg-oss tarball checksum verification failed!"; \ + exit 1; \ + fi \ + && tar xzvf ${REVISION}.tar.gz \ + && cd pkg-oss-${REVISION} \ + && cd debian \ + && for target in %%BUILDTARGET%%; do \ + make rules-$target; \ + mk-build-deps --install --tool="apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends --yes" \ + debuild-$target/nginx-$NGINX_VERSION/debian/control; \ + done \ + && make %%BUILDTARGET%% \ ) \ # we don't remove APT lists here because they get re-downloaded and removed later \ @@ -93,6 +123,7 @@ RUN set -x \ COPY docker-entrypoint.sh / COPY 10-listen-on-ipv6-by-default.sh /docker-entrypoint.d +COPY 15-local-resolvers.envsh /docker-entrypoint.d COPY 20-envsubst-on-templates.sh /docker-entrypoint.d COPY 30-tune-worker-processes.sh /docker-entrypoint.d ENTRYPOINT ["/docker-entrypoint.sh"] diff --git a/LICENSE b/LICENSE index bc1d673f0..f5af4aac9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (C) 2011-2016 Nginx, Inc. +Copyright (C) 2011-2023 F5, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/README.md b/README.md index 5fa769cb4..d23812adf 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,41 @@ +[![Project Status: Active – The project has reached a stable, usable state and is being actively developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active) +[![Community Support](https://badgen.net/badge/support/community/cyan?icon=awesome)](https://github.com/nginx/docker-nginx/blob/master/SUPPORT.md) +[![Community Forum](https://img.shields.io/badge/community-forum-009639?logo=discourse&link=https%3A%2F%2Fcommunity.nginx.org)](https://community.nginx.org) +[![License](https://img.shields.io/badge/License-BSD_2--Clause-blue.svg)](https://opensource.org/license/bsd-2-clause) +[![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](/CODE_OF_CONDUCT.md) + # About this Repo -This is the Git repo of the official Docker image for [nginx](https://registry.hub.docker.com/_/nginx/). See the -Hub page for the full readme on how to use the Docker image and for information -regarding contributing and issues. +## Maintained by: [the NGINX Docker Maintainers](https://github.com/nginx/docker-nginx) + +This is the Git repo of the [Docker "Official Image"](https://github.com/docker-library/official-images#what-are-official-images) for [`nginx`](https://hub.docker.com/_/nginx/). See [the Docker Hub page](https://hub.docker.com/_/nginx/) for the full readme on how to use this Docker image and for information regarding contributing and issues. -The full readme is generated over in [docker-library/docs](https://github.com/docker-library/docs), -specifically in [docker-library/docs/nginx](https://github.com/docker-library/docs/tree/master/nginx). +The [full image description on Docker Hub](https://hub.docker.com/_/nginx/) is generated/maintained over in [the docker-library/docs repository](https://github.com/docker-library/docs), specifically in [the `nginx` directory](https://github.com/docker-library/docs/tree/master/nginx). The changelog for NGINX releases is available at [nginx.org changes page](https://nginx.org/en/CHANGES). + +## See a change merged here that doesn't show up on Docker Hub yet? + +For more information about the full official images change lifecycle, see [the "An image's source changed in Git, now what?" FAQ entry](https://github.com/docker-library/faq#an-images-source-changed-in-git-now-what). + +For outstanding `nginx` image PRs, check [PRs with the "library/nginx" label on the official-images repository](https://github.com/docker-library/official-images/labels/library%2Fnginx). For the current "source of truth" for [`nginx`](https://hub.docker.com/_/nginx/), see [the `library/nginx` file in the official-images repository](https://github.com/docker-library/official-images/blob/master/library/nginx). + +## Contributing + +Please see the [contributing guide](/CONTRIBUTING.md) for guidelines on how to best contribute to this project. + +## License + +[BSD 2-Clause](/LICENSE) + +© [F5, Inc.](https://www.f5.com/) 2014-2025 + +--- + +- [![build status badge](https://img.shields.io/github/actions/workflow/status/nginx/docker-nginx/ci.yml?branch=master&label=GitHub%20CI)](https://github.com/nginx/docker-nginx/actions?query=workflow%3A%22GitHub+CI%22+branch%3Amaster) + +| Build | Status | Badges | (per-arch) | +|:-:|:-:|:-:|:-:| +| [![amd64 build status badge](https://img.shields.io/jenkins/s/https/doi-janky.infosiftr.net/job/multiarch/job/amd64/job/nginx.svg?label=amd64)](https://doi-janky.infosiftr.net/job/multiarch/job/amd64/job/nginx/) | [![arm32v5 build status badge](https://img.shields.io/jenkins/s/https/doi-janky.infosiftr.net/job/multiarch/job/arm32v5/job/nginx.svg?label=arm32v5)](https://doi-janky.infosiftr.net/job/multiarch/job/arm32v5/job/nginx/) | [![arm32v6 build status badge](https://img.shields.io/jenkins/s/https/doi-janky.infosiftr.net/job/multiarch/job/arm32v6/job/nginx.svg?label=arm32v6)](https://doi-janky.infosiftr.net/job/multiarch/job/arm32v6/job/nginx/) | [![arm32v7 build status badge](https://img.shields.io/jenkins/s/https/doi-janky.infosiftr.net/job/multiarch/job/arm32v7/job/nginx.svg?label=arm32v7)](https://doi-janky.infosiftr.net/job/multiarch/job/arm32v7/job/nginx/) | +| [![arm64v8 build status badge](https://img.shields.io/jenkins/s/https/doi-janky.infosiftr.net/job/multiarch/job/arm64v8/job/nginx.svg?label=arm64v8)](https://doi-janky.infosiftr.net/job/multiarch/job/arm64v8/job/nginx/) | [![i386 build status badge](https://img.shields.io/jenkins/s/https/doi-janky.infosiftr.net/job/multiarch/job/i386/job/nginx.svg?label=i386)](https://doi-janky.infosiftr.net/job/multiarch/job/i386/job/nginx/) | [![mips64le build status badge](https://img.shields.io/jenkins/s/https/doi-janky.infosiftr.net/job/multiarch/job/mips64le/job/nginx.svg?label=mips64le)](https://doi-janky.infosiftr.net/job/multiarch/job/mips64le/job/nginx/) | [![ppc64le build status badge](https://img.shields.io/jenkins/s/https/doi-janky.infosiftr.net/job/multiarch/job/ppc64le/job/nginx.svg?label=ppc64le)](https://doi-janky.infosiftr.net/job/multiarch/job/ppc64le/job/nginx/) | +| [![s390x build status badge](https://img.shields.io/jenkins/s/https/doi-janky.infosiftr.net/job/multiarch/job/s390x/job/nginx.svg?label=s390x)](https://doi-janky.infosiftr.net/job/multiarch/job/s390x/job/nginx/) | [![put-shared build status badge](https://img.shields.io/jenkins/s/https/doi-janky.infosiftr.net/job/put-shared/job/light/job/nginx.svg?label=put-shared)](https://doi-janky.infosiftr.net/job/put-shared/job/light/job/nginx/) | diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..bf09fe02e --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,14 @@ +# Security Policy + +## Latest Versions + +We advise users to run or update to the most recent release of the NGINX Docker image. Older versions of the NGINX Docker image may not have all enhancements and/or bug fixes applied to them. + +## Reporting a Vulnerability + +The F5 Security Incident Response Team (F5 SIRT) offers two methods to easily report potential security vulnerabilities: + +- If you’re an F5 customer with an active support contract, please contact [F5 Technical Support](https://www.f5.com/support). +- If you aren’t an F5 customer, please report any potential or current instances of security vulnerabilities in any F5 product to the F5 Security Incident Response Team at . + +For more information, please read the F5 SIRT vulnerability reporting guidelines available at [https://www.f5.com/support/report-a-vulnerability](https://www.f5.com/support/report-a-vulnerability). diff --git a/SUPPORT.md b/SUPPORT.md new file mode 100644 index 000000000..5e9434084 --- /dev/null +++ b/SUPPORT.md @@ -0,0 +1,37 @@ +# Support + +## Ask a Question + +We use GitHub for tracking bugs and feature requests related to this project. + +Don't know how something in this project works? Curious if this project can achieve your desired functionality? Please open an issue on GitHub with the label `question`. Alternatively, start a GitHub discussion! + +## NGINX Specific Questions and/or Issues + +This isn't the right place to get support for NGINX specific questions, but the following resources are available below. Thanks for your understanding! + +### Community Forum + +We have a community [forum](https://community.nginx.org/)! If you have any questions and/or issues, try checking out the [`Troubleshooting`](https://community.nginx.org/c/troubleshooting/8) and [`How do I...?`](https://community.nginx.org/c/how-do-i/9) categories. Both fellow community members and NGINXers might be able to help you! :) + +### Documentation + +For a comprehensive list of all NGINX directives, check out . + +For a comprehensive list of administration and deployment guides for all NGINX products, check out . + +### Mailing List + +Want to get in touch with the NGINX development team directly? Try using the relevant mailing list found at ! + +## Contributing + +Please see the [contributing guide](/CONTRIBUTING.md) for guidelines on how to best contribute to this project. + +## Commercial Support + +Commercial support for this project may be available. Please get in touch with [NGINX sales](https://www.f5.com/products/get-f5/) or check your contract details for more information! + +## Community Support + +Community support is offered on a best effort basis through either GitHub issues/PRs/discussions or through any of our active communities. diff --git a/entrypoint/10-listen-on-ipv6-by-default.sh b/entrypoint/10-listen-on-ipv6-by-default.sh index 9585152ba..61a901dee 100755 --- a/entrypoint/10-listen-on-ipv6-by-default.sh +++ b/entrypoint/10-listen-on-ipv6-by-default.sh @@ -3,52 +3,58 @@ set -e -ME=$(basename $0) +entrypoint_log() { + if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then + echo "$@" + fi +} + +ME=$(basename "$0") DEFAULT_CONF_FILE="etc/nginx/conf.d/default.conf" # check if we have ipv6 available if [ ! -f "/proc/net/if_inet6" ]; then - echo >&3 "$ME: info: ipv6 not available" + entrypoint_log "$ME: info: ipv6 not available" exit 0 fi if [ ! -f "/$DEFAULT_CONF_FILE" ]; then - echo >&3 "$ME: info: /$DEFAULT_CONF_FILE is not a file or does not exist" + entrypoint_log "$ME: info: /$DEFAULT_CONF_FILE is not a file or does not exist" exit 0 fi # check if the file can be modified, e.g. not on a r/o filesystem -touch /$DEFAULT_CONF_FILE 2>/dev/null || { echo >&3 "$ME: info: can not modify /$DEFAULT_CONF_FILE (read-only file system?)"; exit 0; } +touch /$DEFAULT_CONF_FILE 2>/dev/null || { entrypoint_log "$ME: info: can not modify /$DEFAULT_CONF_FILE (read-only file system?)"; exit 0; } # check if the file is already modified, e.g. on a container restart -grep -q "listen \[::]\:80;" /$DEFAULT_CONF_FILE && { echo >&3 "$ME: info: IPv6 listen already enabled"; exit 0; } +grep -q "listen \[::\]:80;" /$DEFAULT_CONF_FILE && { entrypoint_log "$ME: info: IPv6 listen already enabled"; exit 0; } if [ -f "/etc/os-release" ]; then . /etc/os-release else - echo >&3 "$ME: info: can not guess the operating system" + entrypoint_log "$ME: info: can not guess the operating system" exit 0 fi -echo >&3 "$ME: info: Getting the checksum of /$DEFAULT_CONF_FILE" +entrypoint_log "$ME: info: Getting the checksum of /$DEFAULT_CONF_FILE" case "$ID" in "debian") CHECKSUM=$(dpkg-query --show --showformat='${Conffiles}\n' nginx | grep $DEFAULT_CONF_FILE | cut -d' ' -f 3) echo "$CHECKSUM /$DEFAULT_CONF_FILE" | md5sum -c - >/dev/null 2>&1 || { - echo >&3 "$ME: info: /$DEFAULT_CONF_FILE differs from the packaged version" + entrypoint_log "$ME: info: /$DEFAULT_CONF_FILE differs from the packaged version" exit 0 } ;; "alpine") CHECKSUM=$(apk manifest nginx 2>/dev/null| grep $DEFAULT_CONF_FILE | cut -d' ' -f 1 | cut -d ':' -f 2) echo "$CHECKSUM /$DEFAULT_CONF_FILE" | sha1sum -c - >/dev/null 2>&1 || { - echo >&3 "$ME: info: /$DEFAULT_CONF_FILE differs from the packaged version" + entrypoint_log "$ME: info: /$DEFAULT_CONF_FILE differs from the packaged version" exit 0 } ;; *) - echo >&3 "$ME: info: Unsupported distribution" + entrypoint_log "$ME: info: Unsupported distribution" exit 0 ;; esac @@ -56,6 +62,6 @@ esac # enable ipv6 on default.conf listen sockets sed -i -E 's,listen 80;,listen 80;\n listen [::]:80;,' /$DEFAULT_CONF_FILE -echo >&3 "$ME: info: Enabled listen on IPv6 in /$DEFAULT_CONF_FILE" +entrypoint_log "$ME: info: Enabled listen on IPv6 in /$DEFAULT_CONF_FILE" exit 0 diff --git a/entrypoint/15-local-resolvers.envsh b/entrypoint/15-local-resolvers.envsh new file mode 100755 index 000000000..e830ddacd --- /dev/null +++ b/entrypoint/15-local-resolvers.envsh @@ -0,0 +1,15 @@ +#!/bin/sh +# vim:sw=2:ts=2:sts=2:et + +set -eu + +LC_ALL=C +PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin + +[ "${NGINX_ENTRYPOINT_LOCAL_RESOLVERS:-}" ] || return 0 + +NGINX_LOCAL_RESOLVERS=$(awk 'BEGIN{ORS=" "} $1=="nameserver" {if ($2 ~ ":") {print "["$2"]"} else {print $2}}' /etc/resolv.conf) + +NGINX_LOCAL_RESOLVERS="${NGINX_LOCAL_RESOLVERS% }" + +export NGINX_LOCAL_RESOLVERS diff --git a/entrypoint/20-envsubst-on-templates.sh b/entrypoint/20-envsubst-on-templates.sh index 4f330295b..3804165c9 100755 --- a/entrypoint/20-envsubst-on-templates.sh +++ b/entrypoint/20-envsubst-on-templates.sh @@ -2,29 +2,75 @@ set -e -ME=$(basename $0) +ME=$(basename "$0") + +entrypoint_log() { + if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then + echo "$@" + fi +} + +add_stream_block() { + local conffile="/etc/nginx/nginx.conf" + + if grep -q -E "\s*stream\s*\{" "$conffile"; then + entrypoint_log "$ME: $conffile contains a stream block; include $stream_output_dir/*.conf to enable stream templates" + else + # check if the file can be modified, e.g. not on a r/o filesystem + touch "$conffile" 2>/dev/null || { entrypoint_log "$ME: info: can not modify $conffile (read-only file system?)"; exit 0; } + entrypoint_log "$ME: Appending stream block to $conffile to include $stream_output_dir/*.conf" + cat << END >> "$conffile" +# added by "$ME" on "$(date)" +stream { + include $stream_output_dir/*.conf; +} +END + fi +} auto_envsubst() { local template_dir="${NGINX_ENVSUBST_TEMPLATE_DIR:-/etc/nginx/templates}" local suffix="${NGINX_ENVSUBST_TEMPLATE_SUFFIX:-.template}" local output_dir="${NGINX_ENVSUBST_OUTPUT_DIR:-/etc/nginx/conf.d}" + local stream_suffix="${NGINX_ENVSUBST_STREAM_TEMPLATE_SUFFIX:-.stream-template}" + local stream_output_dir="${NGINX_ENVSUBST_STREAM_OUTPUT_DIR:-/etc/nginx/stream-conf.d}" + local filter="${NGINX_ENVSUBST_FILTER:-}" local template defined_envs relative_path output_path subdir - defined_envs=$(printf '${%s} ' $(env | cut -d= -f1)) + defined_envs=$(printf '${%s} ' $(awk "END { for (name in ENVIRON) { print ( name ~ /${filter}/ ) ? name : \"\" } }" < /dev/null )) [ -d "$template_dir" ] || return 0 if [ ! -w "$output_dir" ]; then - echo >&3 "$ME: ERROR: $template_dir exists, but $output_dir is not writable" + entrypoint_log "$ME: ERROR: $template_dir exists, but $output_dir is not writable" return 0 fi find "$template_dir" -follow -type f -name "*$suffix" -print | while read -r template; do - relative_path="${template#$template_dir/}" - output_path="$output_dir/${relative_path%$suffix}" + relative_path="${template#"$template_dir/"}" + output_path="$output_dir/${relative_path%"$suffix"}" subdir=$(dirname "$relative_path") # create a subdirectory where the template file exists mkdir -p "$output_dir/$subdir" - echo >&3 "$ME: Running envsubst on $template to $output_path" + entrypoint_log "$ME: Running envsubst on $template to $output_path" envsubst "$defined_envs" < "$template" > "$output_path" done + + # Print the first file with the stream suffix, this will be false if there are none + if test -n "$(find "$template_dir" -name "*$stream_suffix" -print -quit)"; then + mkdir -p "$stream_output_dir" + if [ ! -w "$stream_output_dir" ]; then + entrypoint_log "$ME: ERROR: $template_dir exists, but $stream_output_dir is not writable" + return 0 + fi + add_stream_block + find "$template_dir" -follow -type f -name "*$stream_suffix" -print | while read -r template; do + relative_path="${template#"$template_dir/"}" + output_path="$stream_output_dir/${relative_path%"$stream_suffix"}" + subdir=$(dirname "$relative_path") + # create a subdirectory where the template file exists + mkdir -p "$stream_output_dir/$subdir" + entrypoint_log "$ME: Running envsubst on $template to $output_path" + envsubst "$defined_envs" < "$template" > "$output_path" + done + fi } auto_envsubst diff --git a/entrypoint/30-tune-worker-processes.sh b/entrypoint/30-tune-worker-processes.sh index 565058715..defb994f3 100755 --- a/entrypoint/30-tune-worker-processes.sh +++ b/entrypoint/30-tune-worker-processes.sh @@ -4,7 +4,7 @@ set -eu LC_ALL=C -ME=$( basename "$0" ) +ME=$(basename "$0") PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin [ "${NGINX_ENTRYPOINT_WORKER_PROCESSES_AUTOTUNE:-}" ] || exit 0 @@ -158,7 +158,7 @@ __EOF__ "/") foundroot="${found##* }$mountpoint" ;; - "$mountpoint") + "$mountpoint" | /../*) foundroot="${found##* }" ;; esac diff --git a/entrypoint/docker-entrypoint.sh b/entrypoint/docker-entrypoint.sh index 72d5cd94e..8ea04f217 100755 --- a/entrypoint/docker-entrypoint.sh +++ b/entrypoint/docker-entrypoint.sh @@ -3,35 +3,44 @@ set -e -if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then - exec 3>&1 -else - exec 3>/dev/null -fi +entrypoint_log() { + if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then + echo "$@" + fi +} -if [ "$1" = "nginx" -o "$1" = "nginx-debug" ]; then +if [ "$1" = "nginx" ] || [ "$1" = "nginx-debug" ]; then if /usr/bin/find "/docker-entrypoint.d/" -mindepth 1 -maxdepth 1 -type f -print -quit 2>/dev/null | read v; then - echo >&3 "$0: /docker-entrypoint.d/ is not empty, will attempt to perform configuration" + entrypoint_log "$0: /docker-entrypoint.d/ is not empty, will attempt to perform configuration" - echo >&3 "$0: Looking for shell scripts in /docker-entrypoint.d/" + entrypoint_log "$0: Looking for shell scripts in /docker-entrypoint.d/" find "/docker-entrypoint.d/" -follow -type f -print | sort -V | while read -r f; do case "$f" in + *.envsh) + if [ -x "$f" ]; then + entrypoint_log "$0: Sourcing $f"; + . "$f" + else + # warn on shell scripts without exec bit + entrypoint_log "$0: Ignoring $f, not executable"; + fi + ;; *.sh) if [ -x "$f" ]; then - echo >&3 "$0: Launching $f"; + entrypoint_log "$0: Launching $f"; "$f" else # warn on shell scripts without exec bit - echo >&3 "$0: Ignoring $f, not executable"; + entrypoint_log "$0: Ignoring $f, not executable"; fi ;; - *) echo >&3 "$0: Ignoring $f";; + *) entrypoint_log "$0: Ignoring $f";; esac done - echo >&3 "$0: Configuration complete; ready for start up" + entrypoint_log "$0: Configuration complete; ready for start up" else - echo >&3 "$0: No files found in /docker-entrypoint.d/, skipping configuration" + entrypoint_log "$0: No files found in /docker-entrypoint.d/, skipping configuration" fi fi diff --git a/generate-stackbrew-library.sh b/generate-stackbrew-library.sh index d9a24d043..13a18cfe0 100755 --- a/generate-stackbrew-library.sh +++ b/generate-stackbrew-library.sh @@ -3,8 +3,8 @@ set -eu declare -A aliases aliases=( - [mainline]='1 1.23 latest' - [stable]='1.22' + [mainline]='1 1.29 latest' + [stable]='1.28' ) self="$(basename "$BASH_SOURCE")" @@ -13,6 +13,12 @@ base=debian versions=( mainline stable ) +declare -A debian_architectures +debian_architectures=( + [mainline]='amd64, arm32v5, arm32v7, arm64v8, i386, ppc64le, riscv64, s390x' + [stable]='amd64, arm32v5, arm32v7, arm64v8, i386, mips64le, ppc64le, s390x' +) + # get the most recent commit which modified any of "$@" fileCommit() { git log -1 --format='format:%H' HEAD -- "$@" @@ -36,10 +42,10 @@ dirCommit() { } cat <<-EOH -# this file is generated via https://github.com/nginxinc/docker-nginx/blob/$(fileCommit "$self")/$self +# this file is generated via https://github.com/nginx/docker-nginx/blob/$(fileCommit "$self")/$self -Maintainers: NGINX Docker Maintainers (@nginxinc) -GitRepo: https://github.com/nginxinc/docker-nginx.git +Maintainers: NGINX Docker Maintainers (@nginx) +GitRepo: https://github.com/nginx/docker-nginx.git EOH # prints "$2$1$3$1...$N" @@ -50,6 +56,8 @@ join() { } for version in "${versions[@]}"; do + debian_otel="debian-otel" + alpine_otel="alpine-otel" commit="$(dirCommit "$version/$base")" fullVersion="$(git show "$commit":"$version/$base/Dockerfile" | awk '$1 == "ENV" && $2 == "NGINX_VERSION" { print $3; exit }')" @@ -60,10 +68,14 @@ for version in "${versions[@]}"; do fi versionAliases+=( ${aliases[$version]:-} ) + debianVersion="$(git show "$commit":"$version/$base/Dockerfile" | awk -F"[-:]" '$1 == "FROM debian" { print $2; exit }')" + debianAliases=( ${versionAliases[@]/%/-$debianVersion} ) + debianAliases=( "${debianAliases[@]//latest-/}" ) + echo cat <<-EOE - Tags: $(join ', ' "${versionAliases[@]}") - Architectures: amd64, arm32v5, arm32v7, arm64v8, i386, mips64le, ppc64le, s390x + Tags: $(join ', ' "${versionAliases[@]}"), $(join ', ' "${debianAliases[@]}") + Architectures: ${debian_architectures[$version]} GitCommit: $commit Directory: $version/$base EOE @@ -72,27 +84,65 @@ for version in "${versions[@]}"; do commit="$(dirCommit "$version/$variant")" variantAliases=( "${versionAliases[@]/%/-perl}" ) + variantAliases+=( "${versionAliases[@]/%/-${variant/debian/$debianVersion}}" ) + variantAliases=( "${variantAliases[@]//latest-/}" ) + + echo + cat <<-EOE + Tags: $(join ', ' "${variantAliases[@]}") + Architectures: ${debian_architectures[$version]} + GitCommit: $commit + Directory: $version/$variant + EOE + done + + for variant in $debian_otel; do + commit="$(dirCommit "$version/$variant")" + + variantAliases=( "${versionAliases[@]/%/-otel}" ) + variantAliases+=( "${versionAliases[@]/%/-${variant/debian/$debianVersion}}" ) + variantAliases=( "${variantAliases[@]//latest-/}" ) + + echo + cat <<-EOE + Tags: $(join ', ' "${variantAliases[@]}") + Architectures: amd64, arm64v8 + GitCommit: $commit + Directory: $version/$variant + EOE + done + + + commit="$(dirCommit "$version/alpine-slim")" + alpineVersion="$(git show "$commit":"$version/alpine-slim/Dockerfile" | awk -F: '$1 == "FROM alpine" { print $2; exit }')" + + for variant in alpine alpine-perl alpine-slim; do + commit="$(dirCommit "$version/$variant")" + + variantAliases=( "${versionAliases[@]/%/-$variant}" ) + variantAliases+=( "${versionAliases[@]/%/-${variant/alpine/alpine$alpineVersion}}" ) variantAliases=( "${variantAliases[@]//latest-/}" ) echo cat <<-EOE Tags: $(join ', ' "${variantAliases[@]}") - Architectures: amd64, arm32v5, arm32v7, arm64v8, i386, mips64le, ppc64le, s390x + Architectures: arm64v8, arm32v6, arm32v7, ppc64le, s390x, i386, amd64, riscv64 GitCommit: $commit Directory: $version/$variant EOE done - for variant in alpine alpine-perl; do + for variant in $alpine_otel; do commit="$(dirCommit "$version/$variant")" variantAliases=( "${versionAliases[@]/%/-$variant}" ) + variantAliases+=( "${versionAliases[@]/%/-${variant/alpine/alpine$alpineVersion}}" ) variantAliases=( "${variantAliases[@]//latest-/}" ) echo cat <<-EOE Tags: $(join ', ' "${variantAliases[@]}") - Architectures: arm64v8, arm32v6, arm32v7, ppc64le, s390x, i386, amd64 + Architectures: amd64, arm64v8 GitCommit: $commit Directory: $version/$variant EOE diff --git a/mainline/alpine-otel/Dockerfile b/mainline/alpine-otel/Dockerfile new file mode 100644 index 000000000..495c61e18 --- /dev/null +++ b/mainline/alpine-otel/Dockerfile @@ -0,0 +1,77 @@ +# +# NOTE: THIS DOCKERFILE IS GENERATED VIA "update.sh" +# +# PLEASE DO NOT EDIT IT DIRECTLY. +# +FROM nginx:1.29.3-alpine + +ENV OTEL_VERSION 0.1.2 + +RUN set -x \ + && apkArch="$(cat /etc/apk/arch)" \ + && nginxPackages=" \ + nginx=${NGINX_VERSION}-r${PKG_RELEASE} \ + nginx-module-xslt=${NGINX_VERSION}-r${DYNPKG_RELEASE} \ + nginx-module-geoip=${NGINX_VERSION}-r${DYNPKG_RELEASE} \ + nginx-module-image-filter=${NGINX_VERSION}-r${DYNPKG_RELEASE} \ + nginx-module-njs=${NGINX_VERSION}.${NJS_VERSION}-r${NJS_RELEASE} \ + nginx-module-otel=${NGINX_VERSION}.${OTEL_VERSION}-r${PKG_RELEASE} \ + " \ +# install prerequisites for public key and pkg-oss checks + && apk add --no-cache --virtual .checksum-deps \ + openssl \ + && case "$apkArch" in \ + x86_64|aarch64) \ +# arches officially built by upstream + apk add -X "https://nginx.org/packages/mainline/alpine/v$(egrep -o '^[0-9]+\.[0-9]+' /etc/alpine-release)/main" --no-cache $nginxPackages \ + ;; \ + *) \ +# we're on an architecture upstream doesn't officially build for +# let's build binaries from the published packaging sources + set -x \ + && tempDir="$(mktemp -d)" \ + && chown nobody:nobody $tempDir \ + && apk add --no-cache --virtual .build-deps \ + gcc \ + libc-dev \ + make \ + openssl-dev \ + pcre2-dev \ + zlib-dev \ + linux-headers \ + cmake \ + bash \ + alpine-sdk \ + findutils \ + curl \ + xz \ + protobuf-dev \ + grpc-dev \ + && su nobody -s /bin/sh -c " \ + export HOME=${tempDir} \ + && cd ${tempDir} \ + && curl -f -L -O https://github.com/nginx/pkg-oss/archive/${NGINX_VERSION}-${PKG_RELEASE}.tar.gz \ + && PKGOSSCHECKSUM=\"249858446828ace0c81ea3e057135aa368f3dab83430cf867bb9fc32598948f29c4bd50908491da704536af1106aa87553f6a76cc126c6833dc9b14dd00564b8 *${NGINX_VERSION}-${PKG_RELEASE}.tar.gz\" \ + && if [ \"\$(openssl sha512 -r ${NGINX_VERSION}-${PKG_RELEASE}.tar.gz)\" = \"\$PKGOSSCHECKSUM\" ]; then \ + echo \"pkg-oss tarball checksum verification succeeded!\"; \ + else \ + echo \"pkg-oss tarball checksum verification failed!\"; \ + exit 1; \ + fi \ + && tar xzvf ${NGINX_VERSION}-${PKG_RELEASE}.tar.gz \ + && cd pkg-oss-${NGINX_VERSION}-${PKG_RELEASE} \ + && cd alpine \ + && make module-otel \ + && apk index --allow-untrusted -o ${tempDir}/packages/alpine/${apkArch}/APKINDEX.tar.gz ${tempDir}/packages/alpine/${apkArch}/*.apk \ + && abuild-sign -k ${tempDir}/.abuild/abuild-key.rsa ${tempDir}/packages/alpine/${apkArch}/APKINDEX.tar.gz \ + " \ + && cp ${tempDir}/.abuild/abuild-key.rsa.pub /etc/apk/keys/ \ + && apk del --no-network .build-deps \ + && apk add -X ${tempDir}/packages/alpine/ --no-cache $nginxPackages \ + ;; \ + esac \ +# remove checksum deps + && apk del --no-network .checksum-deps \ +# if we have leftovers from building, let's purge them (including extra, unnecessary build deps) + && if [ -n "$tempDir" ]; then rm -rf "$tempDir"; fi \ + && if [ -f "/etc/apk/keys/abuild-key.rsa.pub" ]; then rm -f /etc/apk/keys/abuild-key.rsa.pub; fi diff --git a/mainline/alpine-perl/20-envsubst-on-templates.sh b/mainline/alpine-perl/20-envsubst-on-templates.sh deleted file mode 100755 index 4f330295b..000000000 --- a/mainline/alpine-perl/20-envsubst-on-templates.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/sh - -set -e - -ME=$(basename $0) - -auto_envsubst() { - local template_dir="${NGINX_ENVSUBST_TEMPLATE_DIR:-/etc/nginx/templates}" - local suffix="${NGINX_ENVSUBST_TEMPLATE_SUFFIX:-.template}" - local output_dir="${NGINX_ENVSUBST_OUTPUT_DIR:-/etc/nginx/conf.d}" - - local template defined_envs relative_path output_path subdir - defined_envs=$(printf '${%s} ' $(env | cut -d= -f1)) - [ -d "$template_dir" ] || return 0 - if [ ! -w "$output_dir" ]; then - echo >&3 "$ME: ERROR: $template_dir exists, but $output_dir is not writable" - return 0 - fi - find "$template_dir" -follow -type f -name "*$suffix" -print | while read -r template; do - relative_path="${template#$template_dir/}" - output_path="$output_dir/${relative_path%$suffix}" - subdir=$(dirname "$relative_path") - # create a subdirectory where the template file exists - mkdir -p "$output_dir/$subdir" - echo >&3 "$ME: Running envsubst on $template to $output_path" - envsubst "$defined_envs" < "$template" > "$output_path" - done -} - -auto_envsubst - -exit 0 diff --git a/mainline/alpine-perl/30-tune-worker-processes.sh b/mainline/alpine-perl/30-tune-worker-processes.sh deleted file mode 100755 index 565058715..000000000 --- a/mainline/alpine-perl/30-tune-worker-processes.sh +++ /dev/null @@ -1,188 +0,0 @@ -#!/bin/sh -# vim:sw=2:ts=2:sts=2:et - -set -eu - -LC_ALL=C -ME=$( basename "$0" ) -PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin - -[ "${NGINX_ENTRYPOINT_WORKER_PROCESSES_AUTOTUNE:-}" ] || exit 0 - -touch /etc/nginx/nginx.conf 2>/dev/null || { echo >&2 "$ME: error: can not modify /etc/nginx/nginx.conf (read-only file system?)"; exit 0; } - -ceildiv() { - num=$1 - div=$2 - echo $(( (num + div - 1) / div )) -} - -get_cpuset() { - cpusetroot=$1 - cpusetfile=$2 - ncpu=0 - [ -f "$cpusetroot/$cpusetfile" ] || return 1 - for token in $( tr ',' ' ' < "$cpusetroot/$cpusetfile" ); do - case "$token" in - *-*) - count=$( seq $(echo "$token" | tr '-' ' ') | wc -l ) - ncpu=$(( ncpu+count )) - ;; - *) - ncpu=$(( ncpu+1 )) - ;; - esac - done - echo "$ncpu" -} - -get_quota() { - cpuroot=$1 - ncpu=0 - [ -f "$cpuroot/cpu.cfs_quota_us" ] || return 1 - [ -f "$cpuroot/cpu.cfs_period_us" ] || return 1 - cfs_quota=$( cat "$cpuroot/cpu.cfs_quota_us" ) - cfs_period=$( cat "$cpuroot/cpu.cfs_period_us" ) - [ "$cfs_quota" = "-1" ] && return 1 - [ "$cfs_period" = "0" ] && return 1 - ncpu=$( ceildiv "$cfs_quota" "$cfs_period" ) - [ "$ncpu" -gt 0 ] || return 1 - echo "$ncpu" -} - -get_quota_v2() { - cpuroot=$1 - ncpu=0 - [ -f "$cpuroot/cpu.max" ] || return 1 - cfs_quota=$( cut -d' ' -f 1 < "$cpuroot/cpu.max" ) - cfs_period=$( cut -d' ' -f 2 < "$cpuroot/cpu.max" ) - [ "$cfs_quota" = "max" ] && return 1 - [ "$cfs_period" = "0" ] && return 1 - ncpu=$( ceildiv "$cfs_quota" "$cfs_period" ) - [ "$ncpu" -gt 0 ] || return 1 - echo "$ncpu" -} - -get_cgroup_v1_path() { - needle=$1 - found= - foundroot= - mountpoint= - - [ -r "/proc/self/mountinfo" ] || return 1 - [ -r "/proc/self/cgroup" ] || return 1 - - while IFS= read -r line; do - case "$needle" in - "cpuset") - case "$line" in - *cpuset*) - found=$( echo "$line" | cut -d ' ' -f 4,5 ) - break - ;; - esac - ;; - "cpu") - case "$line" in - *cpuset*) - ;; - *cpu,cpuacct*|*cpuacct,cpu|*cpuacct*|*cpu*) - found=$( echo "$line" | cut -d ' ' -f 4,5 ) - break - ;; - esac - esac - done << __EOF__ -$( grep -F -- '- cgroup ' /proc/self/mountinfo ) -__EOF__ - - while IFS= read -r line; do - controller=$( echo "$line" | cut -d: -f 2 ) - case "$needle" in - "cpuset") - case "$controller" in - cpuset) - mountpoint=$( echo "$line" | cut -d: -f 3 ) - break - ;; - esac - ;; - "cpu") - case "$controller" in - cpu,cpuacct|cpuacct,cpu|cpuacct|cpu) - mountpoint=$( echo "$line" | cut -d: -f 3 ) - break - ;; - esac - ;; - esac -done << __EOF__ -$( grep -F -- 'cpu' /proc/self/cgroup ) -__EOF__ - - case "${found%% *}" in - "/") - foundroot="${found##* }$mountpoint" - ;; - "$mountpoint") - foundroot="${found##* }" - ;; - esac - echo "$foundroot" -} - -get_cgroup_v2_path() { - found= - foundroot= - mountpoint= - - [ -r "/proc/self/mountinfo" ] || return 1 - [ -r "/proc/self/cgroup" ] || return 1 - - while IFS= read -r line; do - found=$( echo "$line" | cut -d ' ' -f 4,5 ) - done << __EOF__ -$( grep -F -- '- cgroup2 ' /proc/self/mountinfo ) -__EOF__ - - while IFS= read -r line; do - mountpoint=$( echo "$line" | cut -d: -f 3 ) -done << __EOF__ -$( grep -F -- '0::' /proc/self/cgroup ) -__EOF__ - - case "${found%% *}" in - "") - return 1 - ;; - "/") - foundroot="${found##* }$mountpoint" - ;; - "$mountpoint") - foundroot="${found##* }" - ;; - esac - echo "$foundroot" -} - -ncpu_online=$( getconf _NPROCESSORS_ONLN ) -ncpu_cpuset= -ncpu_quota= -ncpu_cpuset_v2= -ncpu_quota_v2= - -cpuset=$( get_cgroup_v1_path "cpuset" ) && ncpu_cpuset=$( get_cpuset "$cpuset" "cpuset.effective_cpus" ) || ncpu_cpuset=$ncpu_online -cpu=$( get_cgroup_v1_path "cpu" ) && ncpu_quota=$( get_quota "$cpu" ) || ncpu_quota=$ncpu_online -cgroup_v2=$( get_cgroup_v2_path ) && ncpu_cpuset_v2=$( get_cpuset "$cgroup_v2" "cpuset.cpus.effective" ) || ncpu_cpuset_v2=$ncpu_online -cgroup_v2=$( get_cgroup_v2_path ) && ncpu_quota_v2=$( get_quota_v2 "$cgroup_v2" ) || ncpu_quota_v2=$ncpu_online - -ncpu=$( printf "%s\n%s\n%s\n%s\n%s\n" \ - "$ncpu_online" \ - "$ncpu_cpuset" \ - "$ncpu_quota" \ - "$ncpu_cpuset_v2" \ - "$ncpu_quota_v2" \ - | sort -n \ - | head -n 1 ) - -sed -i.bak -r 's/^(worker_processes)(.*)$/# Commented out by '"$ME"' on '"$(date)"'\n#\1\2\n\1 '"$ncpu"';/' /etc/nginx/nginx.conf diff --git a/mainline/alpine-perl/Dockerfile b/mainline/alpine-perl/Dockerfile index 74b16afb1..837daac1f 100644 --- a/mainline/alpine-perl/Dockerfile +++ b/mainline/alpine-perl/Dockerfile @@ -3,26 +3,17 @@ # # PLEASE DO NOT EDIT IT DIRECTLY. # -FROM alpine:3.16 - -LABEL maintainer="NGINX Docker Maintainers " - -ENV NGINX_VERSION 1.23.0 -ENV NJS_VERSION 0.7.5 -ENV PKG_RELEASE 1 +FROM nginx:1.29.3-alpine RUN set -x \ -# create nginx user/group first, to be consistent throughout docker variants - && addgroup -g 101 -S nginx \ - && adduser -S -D -H -u 101 -h /var/cache/nginx -s /sbin/nologin -G nginx -g nginx nginx \ && apkArch="$(cat /etc/apk/arch)" \ && nginxPackages=" \ nginx=${NGINX_VERSION}-r${PKG_RELEASE} \ - nginx-module-xslt=${NGINX_VERSION}-r${PKG_RELEASE} \ - nginx-module-geoip=${NGINX_VERSION}-r${PKG_RELEASE} \ - nginx-module-image-filter=${NGINX_VERSION}-r${PKG_RELEASE} \ - nginx-module-perl=${NGINX_VERSION}-r${PKG_RELEASE} \ - nginx-module-njs=${NGINX_VERSION}.${NJS_VERSION}-r${PKG_RELEASE} \ + nginx-module-xslt=${NGINX_VERSION}-r${DYNPKG_RELEASE} \ + nginx-module-geoip=${NGINX_VERSION}-r${DYNPKG_RELEASE} \ + nginx-module-image-filter=${NGINX_VERSION}-r${DYNPKG_RELEASE} \ + nginx-module-perl=${NGINX_VERSION}-r${DYNPKG_RELEASE} \ + nginx-module-njs=${NGINX_VERSION}.${NJS_VERSION}-r${NJS_RELEASE} \ " \ # install prerequisites for public key and pkg-oss checks && apk add --no-cache --virtual .checksum-deps \ @@ -30,17 +21,7 @@ RUN set -x \ && case "$apkArch" in \ x86_64|aarch64) \ # arches officially built by upstream - set -x \ - && KEY_SHA512="e7fa8303923d9b95db37a77ad46c68fd4755ff935d0a534d26eba83de193c76166c68bfe7f65471bf8881004ef4aa6df3e34689c305662750c0172fca5d8552a *stdin" \ - && wget -O /tmp/nginx_signing.rsa.pub https://nginx.org/keys/nginx_signing.rsa.pub \ - && if [ "$(openssl rsa -pubin -in /tmp/nginx_signing.rsa.pub -text -noout | openssl sha512 -r)" = "$KEY_SHA512" ]; then \ - echo "key verification succeeded!"; \ - mv /tmp/nginx_signing.rsa.pub /etc/apk/keys/; \ - else \ - echo "key verification failed!"; \ - exit 1; \ - fi \ - && apk add -X "https://nginx.org/packages/mainline/alpine/v$(egrep -o '^[0-9]+\.[0-9]+' /etc/alpine-release)/main" --no-cache $nginxPackages \ + apk add -X "https://nginx.org/packages/mainline/alpine/v$(egrep -o '^[0-9]+\.[0-9]+' /etc/alpine-release)/main" --no-cache $nginxPackages \ ;; \ *) \ # we're on an architecture upstream doesn't officially build for @@ -56,19 +37,16 @@ RUN set -x \ pcre2-dev \ zlib-dev \ linux-headers \ - libxslt-dev \ - gd-dev \ - geoip-dev \ perl-dev \ - libedit-dev \ bash \ alpine-sdk \ findutils \ + curl \ && su nobody -s /bin/sh -c " \ export HOME=${tempDir} \ && cd ${tempDir} \ - && curl -f -O https://hg.nginx.org/pkg-oss/archive/${NGINX_VERSION}-${PKG_RELEASE}.tar.gz \ - && PKGOSSCHECKSUM=\"678b1e9ab34777f1a1a1a8717aff0dfa08cc187cf2cf140c084d23205f3ba3af97805e72ebbed49dd7bfcb23bbeca982b150fff5c2a6c96f161ed9085101f1a4 *${NGINX_VERSION}-${PKG_RELEASE}.tar.gz\" \ + && curl -f -L -O https://github.com/nginx/pkg-oss/archive/${NGINX_VERSION}-${PKG_RELEASE}.tar.gz \ + && PKGOSSCHECKSUM=\"249858446828ace0c81ea3e057135aa368f3dab83430cf867bb9fc32598948f29c4bd50908491da704536af1106aa87553f6a76cc126c6833dc9b14dd00564b8 *${NGINX_VERSION}-${PKG_RELEASE}.tar.gz\" \ && if [ \"\$(openssl sha512 -r ${NGINX_VERSION}-${PKG_RELEASE}.tar.gz)\" = \"\$PKGOSSCHECKSUM\" ]; then \ echo \"pkg-oss tarball checksum verification succeeded!\"; \ else \ @@ -78,57 +56,17 @@ RUN set -x \ && tar xzvf ${NGINX_VERSION}-${PKG_RELEASE}.tar.gz \ && cd pkg-oss-${NGINX_VERSION}-${PKG_RELEASE} \ && cd alpine \ - && make all \ - && apk index -o ${tempDir}/packages/alpine/${apkArch}/APKINDEX.tar.gz ${tempDir}/packages/alpine/${apkArch}/*.apk \ + && make module-perl \ + && apk index --allow-untrusted -o ${tempDir}/packages/alpine/${apkArch}/APKINDEX.tar.gz ${tempDir}/packages/alpine/${apkArch}/*.apk \ && abuild-sign -k ${tempDir}/.abuild/abuild-key.rsa ${tempDir}/packages/alpine/${apkArch}/APKINDEX.tar.gz \ " \ && cp ${tempDir}/.abuild/abuild-key.rsa.pub /etc/apk/keys/ \ - && apk del .build-deps \ + && apk del --no-network .build-deps \ && apk add -X ${tempDir}/packages/alpine/ --no-cache $nginxPackages \ ;; \ esac \ # remove checksum deps - && apk del .checksum-deps \ + && apk del --no-network .checksum-deps \ # if we have leftovers from building, let's purge them (including extra, unnecessary build deps) && if [ -n "$tempDir" ]; then rm -rf "$tempDir"; fi \ - && if [ -n "/etc/apk/keys/abuild-key.rsa.pub" ]; then rm -f /etc/apk/keys/abuild-key.rsa.pub; fi \ - && if [ -n "/etc/apk/keys/nginx_signing.rsa.pub" ]; then rm -f /etc/apk/keys/nginx_signing.rsa.pub; fi \ -# Bring in gettext so we can get `envsubst`, then throw -# the rest away. To do this, we need to install `gettext` -# then move `envsubst` out of the way so `gettext` can -# be deleted completely, then move `envsubst` back. - && apk add --no-cache --virtual .gettext gettext \ - && mv /usr/bin/envsubst /tmp/ \ - \ - && runDeps="$( \ - scanelf --needed --nobanner /tmp/envsubst \ - | awk '{ gsub(/,/, "\nso:", $2); print "so:" $2 }' \ - | sort -u \ - | xargs -r apk info --installed \ - | sort -u \ - )" \ - && apk add --no-cache $runDeps \ - && apk del .gettext \ - && mv /tmp/envsubst /usr/local/bin/ \ -# Bring in tzdata so users could set the timezones through the environment -# variables - && apk add --no-cache tzdata \ -# Bring in curl and ca-certificates to make registering on DNS SD easier - && apk add --no-cache curl ca-certificates \ -# forward request and error logs to docker log collector - && ln -sf /dev/stdout /var/log/nginx/access.log \ - && ln -sf /dev/stderr /var/log/nginx/error.log \ -# create a docker-entrypoint.d directory - && mkdir /docker-entrypoint.d - -COPY docker-entrypoint.sh / -COPY 10-listen-on-ipv6-by-default.sh /docker-entrypoint.d -COPY 20-envsubst-on-templates.sh /docker-entrypoint.d -COPY 30-tune-worker-processes.sh /docker-entrypoint.d -ENTRYPOINT ["/docker-entrypoint.sh"] - -EXPOSE 80 - -STOPSIGNAL SIGQUIT - -CMD ["nginx", "-g", "daemon off;"] + && if [ -f "/etc/apk/keys/abuild-key.rsa.pub" ]; then rm -f /etc/apk/keys/abuild-key.rsa.pub; fi diff --git a/mainline/alpine-perl/docker-entrypoint.sh b/mainline/alpine-perl/docker-entrypoint.sh deleted file mode 100755 index 72d5cd94e..000000000 --- a/mainline/alpine-perl/docker-entrypoint.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh -# vim:sw=4:ts=4:et - -set -e - -if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then - exec 3>&1 -else - exec 3>/dev/null -fi - -if [ "$1" = "nginx" -o "$1" = "nginx-debug" ]; then - if /usr/bin/find "/docker-entrypoint.d/" -mindepth 1 -maxdepth 1 -type f -print -quit 2>/dev/null | read v; then - echo >&3 "$0: /docker-entrypoint.d/ is not empty, will attempt to perform configuration" - - echo >&3 "$0: Looking for shell scripts in /docker-entrypoint.d/" - find "/docker-entrypoint.d/" -follow -type f -print | sort -V | while read -r f; do - case "$f" in - *.sh) - if [ -x "$f" ]; then - echo >&3 "$0: Launching $f"; - "$f" - else - # warn on shell scripts without exec bit - echo >&3 "$0: Ignoring $f, not executable"; - fi - ;; - *) echo >&3 "$0: Ignoring $f";; - esac - done - - echo >&3 "$0: Configuration complete; ready for start up" - else - echo >&3 "$0: No files found in /docker-entrypoint.d/, skipping configuration" - fi -fi - -exec "$@" diff --git a/mainline/alpine-perl/10-listen-on-ipv6-by-default.sh b/mainline/alpine-slim/10-listen-on-ipv6-by-default.sh similarity index 53% rename from mainline/alpine-perl/10-listen-on-ipv6-by-default.sh rename to mainline/alpine-slim/10-listen-on-ipv6-by-default.sh index 9585152ba..61a901dee 100755 --- a/mainline/alpine-perl/10-listen-on-ipv6-by-default.sh +++ b/mainline/alpine-slim/10-listen-on-ipv6-by-default.sh @@ -3,52 +3,58 @@ set -e -ME=$(basename $0) +entrypoint_log() { + if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then + echo "$@" + fi +} + +ME=$(basename "$0") DEFAULT_CONF_FILE="etc/nginx/conf.d/default.conf" # check if we have ipv6 available if [ ! -f "/proc/net/if_inet6" ]; then - echo >&3 "$ME: info: ipv6 not available" + entrypoint_log "$ME: info: ipv6 not available" exit 0 fi if [ ! -f "/$DEFAULT_CONF_FILE" ]; then - echo >&3 "$ME: info: /$DEFAULT_CONF_FILE is not a file or does not exist" + entrypoint_log "$ME: info: /$DEFAULT_CONF_FILE is not a file or does not exist" exit 0 fi # check if the file can be modified, e.g. not on a r/o filesystem -touch /$DEFAULT_CONF_FILE 2>/dev/null || { echo >&3 "$ME: info: can not modify /$DEFAULT_CONF_FILE (read-only file system?)"; exit 0; } +touch /$DEFAULT_CONF_FILE 2>/dev/null || { entrypoint_log "$ME: info: can not modify /$DEFAULT_CONF_FILE (read-only file system?)"; exit 0; } # check if the file is already modified, e.g. on a container restart -grep -q "listen \[::]\:80;" /$DEFAULT_CONF_FILE && { echo >&3 "$ME: info: IPv6 listen already enabled"; exit 0; } +grep -q "listen \[::\]:80;" /$DEFAULT_CONF_FILE && { entrypoint_log "$ME: info: IPv6 listen already enabled"; exit 0; } if [ -f "/etc/os-release" ]; then . /etc/os-release else - echo >&3 "$ME: info: can not guess the operating system" + entrypoint_log "$ME: info: can not guess the operating system" exit 0 fi -echo >&3 "$ME: info: Getting the checksum of /$DEFAULT_CONF_FILE" +entrypoint_log "$ME: info: Getting the checksum of /$DEFAULT_CONF_FILE" case "$ID" in "debian") CHECKSUM=$(dpkg-query --show --showformat='${Conffiles}\n' nginx | grep $DEFAULT_CONF_FILE | cut -d' ' -f 3) echo "$CHECKSUM /$DEFAULT_CONF_FILE" | md5sum -c - >/dev/null 2>&1 || { - echo >&3 "$ME: info: /$DEFAULT_CONF_FILE differs from the packaged version" + entrypoint_log "$ME: info: /$DEFAULT_CONF_FILE differs from the packaged version" exit 0 } ;; "alpine") CHECKSUM=$(apk manifest nginx 2>/dev/null| grep $DEFAULT_CONF_FILE | cut -d' ' -f 1 | cut -d ':' -f 2) echo "$CHECKSUM /$DEFAULT_CONF_FILE" | sha1sum -c - >/dev/null 2>&1 || { - echo >&3 "$ME: info: /$DEFAULT_CONF_FILE differs from the packaged version" + entrypoint_log "$ME: info: /$DEFAULT_CONF_FILE differs from the packaged version" exit 0 } ;; *) - echo >&3 "$ME: info: Unsupported distribution" + entrypoint_log "$ME: info: Unsupported distribution" exit 0 ;; esac @@ -56,6 +62,6 @@ esac # enable ipv6 on default.conf listen sockets sed -i -E 's,listen 80;,listen 80;\n listen [::]:80;,' /$DEFAULT_CONF_FILE -echo >&3 "$ME: info: Enabled listen on IPv6 in /$DEFAULT_CONF_FILE" +entrypoint_log "$ME: info: Enabled listen on IPv6 in /$DEFAULT_CONF_FILE" exit 0 diff --git a/mainline/alpine-slim/15-local-resolvers.envsh b/mainline/alpine-slim/15-local-resolvers.envsh new file mode 100755 index 000000000..e830ddacd --- /dev/null +++ b/mainline/alpine-slim/15-local-resolvers.envsh @@ -0,0 +1,15 @@ +#!/bin/sh +# vim:sw=2:ts=2:sts=2:et + +set -eu + +LC_ALL=C +PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin + +[ "${NGINX_ENTRYPOINT_LOCAL_RESOLVERS:-}" ] || return 0 + +NGINX_LOCAL_RESOLVERS=$(awk 'BEGIN{ORS=" "} $1=="nameserver" {if ($2 ~ ":") {print "["$2"]"} else {print $2}}' /etc/resolv.conf) + +NGINX_LOCAL_RESOLVERS="${NGINX_LOCAL_RESOLVERS% }" + +export NGINX_LOCAL_RESOLVERS diff --git a/mainline/alpine-slim/20-envsubst-on-templates.sh b/mainline/alpine-slim/20-envsubst-on-templates.sh new file mode 100755 index 000000000..3804165c9 --- /dev/null +++ b/mainline/alpine-slim/20-envsubst-on-templates.sh @@ -0,0 +1,78 @@ +#!/bin/sh + +set -e + +ME=$(basename "$0") + +entrypoint_log() { + if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then + echo "$@" + fi +} + +add_stream_block() { + local conffile="/etc/nginx/nginx.conf" + + if grep -q -E "\s*stream\s*\{" "$conffile"; then + entrypoint_log "$ME: $conffile contains a stream block; include $stream_output_dir/*.conf to enable stream templates" + else + # check if the file can be modified, e.g. not on a r/o filesystem + touch "$conffile" 2>/dev/null || { entrypoint_log "$ME: info: can not modify $conffile (read-only file system?)"; exit 0; } + entrypoint_log "$ME: Appending stream block to $conffile to include $stream_output_dir/*.conf" + cat << END >> "$conffile" +# added by "$ME" on "$(date)" +stream { + include $stream_output_dir/*.conf; +} +END + fi +} + +auto_envsubst() { + local template_dir="${NGINX_ENVSUBST_TEMPLATE_DIR:-/etc/nginx/templates}" + local suffix="${NGINX_ENVSUBST_TEMPLATE_SUFFIX:-.template}" + local output_dir="${NGINX_ENVSUBST_OUTPUT_DIR:-/etc/nginx/conf.d}" + local stream_suffix="${NGINX_ENVSUBST_STREAM_TEMPLATE_SUFFIX:-.stream-template}" + local stream_output_dir="${NGINX_ENVSUBST_STREAM_OUTPUT_DIR:-/etc/nginx/stream-conf.d}" + local filter="${NGINX_ENVSUBST_FILTER:-}" + + local template defined_envs relative_path output_path subdir + defined_envs=$(printf '${%s} ' $(awk "END { for (name in ENVIRON) { print ( name ~ /${filter}/ ) ? name : \"\" } }" < /dev/null )) + [ -d "$template_dir" ] || return 0 + if [ ! -w "$output_dir" ]; then + entrypoint_log "$ME: ERROR: $template_dir exists, but $output_dir is not writable" + return 0 + fi + find "$template_dir" -follow -type f -name "*$suffix" -print | while read -r template; do + relative_path="${template#"$template_dir/"}" + output_path="$output_dir/${relative_path%"$suffix"}" + subdir=$(dirname "$relative_path") + # create a subdirectory where the template file exists + mkdir -p "$output_dir/$subdir" + entrypoint_log "$ME: Running envsubst on $template to $output_path" + envsubst "$defined_envs" < "$template" > "$output_path" + done + + # Print the first file with the stream suffix, this will be false if there are none + if test -n "$(find "$template_dir" -name "*$stream_suffix" -print -quit)"; then + mkdir -p "$stream_output_dir" + if [ ! -w "$stream_output_dir" ]; then + entrypoint_log "$ME: ERROR: $template_dir exists, but $stream_output_dir is not writable" + return 0 + fi + add_stream_block + find "$template_dir" -follow -type f -name "*$stream_suffix" -print | while read -r template; do + relative_path="${template#"$template_dir/"}" + output_path="$stream_output_dir/${relative_path%"$stream_suffix"}" + subdir=$(dirname "$relative_path") + # create a subdirectory where the template file exists + mkdir -p "$stream_output_dir/$subdir" + entrypoint_log "$ME: Running envsubst on $template to $output_path" + envsubst "$defined_envs" < "$template" > "$output_path" + done + fi +} + +auto_envsubst + +exit 0 diff --git a/mainline/alpine/30-tune-worker-processes.sh b/mainline/alpine-slim/30-tune-worker-processes.sh similarity index 98% rename from mainline/alpine/30-tune-worker-processes.sh rename to mainline/alpine-slim/30-tune-worker-processes.sh index 565058715..defb994f3 100755 --- a/mainline/alpine/30-tune-worker-processes.sh +++ b/mainline/alpine-slim/30-tune-worker-processes.sh @@ -4,7 +4,7 @@ set -eu LC_ALL=C -ME=$( basename "$0" ) +ME=$(basename "$0") PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin [ "${NGINX_ENTRYPOINT_WORKER_PROCESSES_AUTOTUNE:-}" ] || exit 0 @@ -158,7 +158,7 @@ __EOF__ "/") foundroot="${found##* }$mountpoint" ;; - "$mountpoint") + "$mountpoint" | /../*) foundroot="${found##* }" ;; esac diff --git a/mainline/alpine-slim/Dockerfile b/mainline/alpine-slim/Dockerfile new file mode 100644 index 000000000..9fe90d6f6 --- /dev/null +++ b/mainline/alpine-slim/Dockerfile @@ -0,0 +1,108 @@ +# +# NOTE: THIS DOCKERFILE IS GENERATED VIA "update.sh" +# +# PLEASE DO NOT EDIT IT DIRECTLY. +# +FROM alpine:3.22 + +LABEL maintainer="NGINX Docker Maintainers " + +ENV NGINX_VERSION 1.29.3 +ENV PKG_RELEASE 1 +ENV DYNPKG_RELEASE 1 + +RUN set -x \ +# create nginx user/group first, to be consistent throughout docker variants + && addgroup -g 101 -S nginx \ + && adduser -S -D -H -u 101 -h /var/cache/nginx -s /sbin/nologin -G nginx -g nginx nginx \ + && apkArch="$(cat /etc/apk/arch)" \ + && nginxPackages=" \ + nginx=${NGINX_VERSION}-r${PKG_RELEASE} \ + " \ +# install prerequisites for public key and pkg-oss checks + && apk add --no-cache --virtual .checksum-deps \ + openssl \ + && case "$apkArch" in \ + x86_64|aarch64) \ +# arches officially built by upstream + set -x \ + && KEY_SHA512="e09fa32f0a0eab2b879ccbbc4d0e4fb9751486eedda75e35fac65802cc9faa266425edf83e261137a2f4d16281ce2c1a5f4502930fe75154723da014214f0655" \ + && wget -O /tmp/nginx_signing.rsa.pub https://nginx.org/keys/nginx_signing.rsa.pub \ + && if echo "$KEY_SHA512 */tmp/nginx_signing.rsa.pub" | sha512sum -c -; then \ + echo "key verification succeeded!"; \ + mv /tmp/nginx_signing.rsa.pub /etc/apk/keys/; \ + else \ + echo "key verification failed!"; \ + exit 1; \ + fi \ + && apk add -X "https://nginx.org/packages/mainline/alpine/v$(egrep -o '^[0-9]+\.[0-9]+' /etc/alpine-release)/main" --no-cache $nginxPackages \ + ;; \ + *) \ +# we're on an architecture upstream doesn't officially build for +# let's build binaries from the published packaging sources + set -x \ + && tempDir="$(mktemp -d)" \ + && chown nobody:nobody $tempDir \ + && apk add --no-cache --virtual .build-deps \ + gcc \ + libc-dev \ + make \ + openssl-dev \ + pcre2-dev \ + zlib-dev \ + linux-headers \ + bash \ + alpine-sdk \ + findutils \ + curl \ + && su nobody -s /bin/sh -c " \ + export HOME=${tempDir} \ + && cd ${tempDir} \ + && curl -f -L -O https://github.com/nginx/pkg-oss/archive/${NGINX_VERSION}-${PKG_RELEASE}.tar.gz \ + && PKGOSSCHECKSUM=\"249858446828ace0c81ea3e057135aa368f3dab83430cf867bb9fc32598948f29c4bd50908491da704536af1106aa87553f6a76cc126c6833dc9b14dd00564b8 *${NGINX_VERSION}-${PKG_RELEASE}.tar.gz\" \ + && if [ \"\$(openssl sha512 -r ${NGINX_VERSION}-${PKG_RELEASE}.tar.gz)\" = \"\$PKGOSSCHECKSUM\" ]; then \ + echo \"pkg-oss tarball checksum verification succeeded!\"; \ + else \ + echo \"pkg-oss tarball checksum verification failed!\"; \ + exit 1; \ + fi \ + && tar xzvf ${NGINX_VERSION}-${PKG_RELEASE}.tar.gz \ + && cd pkg-oss-${NGINX_VERSION}-${PKG_RELEASE} \ + && cd alpine \ + && make base \ + && apk index --allow-untrusted -o ${tempDir}/packages/alpine/${apkArch}/APKINDEX.tar.gz ${tempDir}/packages/alpine/${apkArch}/*.apk \ + && abuild-sign -k ${tempDir}/.abuild/abuild-key.rsa ${tempDir}/packages/alpine/${apkArch}/APKINDEX.tar.gz \ + " \ + && cp ${tempDir}/.abuild/abuild-key.rsa.pub /etc/apk/keys/ \ + && apk del --no-network .build-deps \ + && apk add -X ${tempDir}/packages/alpine/ --no-cache $nginxPackages \ + ;; \ + esac \ +# remove checksum deps + && apk del --no-network .checksum-deps \ +# if we have leftovers from building, let's purge them (including extra, unnecessary build deps) + && if [ -n "$tempDir" ]; then rm -rf "$tempDir"; fi \ + && if [ -f "/etc/apk/keys/abuild-key.rsa.pub" ]; then rm -f /etc/apk/keys/abuild-key.rsa.pub; fi \ +# Add `envsubst` for templating environment variables + && apk add --no-cache gettext-envsubst \ +# Bring in tzdata so users could set the timezones through the environment +# variables + && apk add --no-cache tzdata \ +# forward request and error logs to docker log collector + && ln -sf /dev/stdout /var/log/nginx/access.log \ + && ln -sf /dev/stderr /var/log/nginx/error.log \ +# create a docker-entrypoint.d directory + && mkdir /docker-entrypoint.d + +COPY docker-entrypoint.sh / +COPY 10-listen-on-ipv6-by-default.sh /docker-entrypoint.d +COPY 15-local-resolvers.envsh /docker-entrypoint.d +COPY 20-envsubst-on-templates.sh /docker-entrypoint.d +COPY 30-tune-worker-processes.sh /docker-entrypoint.d +ENTRYPOINT ["/docker-entrypoint.sh"] + +EXPOSE 80 + +STOPSIGNAL SIGQUIT + +CMD ["nginx", "-g", "daemon off;"] diff --git a/mainline/alpine-slim/docker-entrypoint.sh b/mainline/alpine-slim/docker-entrypoint.sh new file mode 100755 index 000000000..8ea04f217 --- /dev/null +++ b/mainline/alpine-slim/docker-entrypoint.sh @@ -0,0 +1,47 @@ +#!/bin/sh +# vim:sw=4:ts=4:et + +set -e + +entrypoint_log() { + if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then + echo "$@" + fi +} + +if [ "$1" = "nginx" ] || [ "$1" = "nginx-debug" ]; then + if /usr/bin/find "/docker-entrypoint.d/" -mindepth 1 -maxdepth 1 -type f -print -quit 2>/dev/null | read v; then + entrypoint_log "$0: /docker-entrypoint.d/ is not empty, will attempt to perform configuration" + + entrypoint_log "$0: Looking for shell scripts in /docker-entrypoint.d/" + find "/docker-entrypoint.d/" -follow -type f -print | sort -V | while read -r f; do + case "$f" in + *.envsh) + if [ -x "$f" ]; then + entrypoint_log "$0: Sourcing $f"; + . "$f" + else + # warn on shell scripts without exec bit + entrypoint_log "$0: Ignoring $f, not executable"; + fi + ;; + *.sh) + if [ -x "$f" ]; then + entrypoint_log "$0: Launching $f"; + "$f" + else + # warn on shell scripts without exec bit + entrypoint_log "$0: Ignoring $f, not executable"; + fi + ;; + *) entrypoint_log "$0: Ignoring $f";; + esac + done + + entrypoint_log "$0: Configuration complete; ready for start up" + else + entrypoint_log "$0: No files found in /docker-entrypoint.d/, skipping configuration" + fi +fi + +exec "$@" diff --git a/mainline/alpine/20-envsubst-on-templates.sh b/mainline/alpine/20-envsubst-on-templates.sh deleted file mode 100755 index 4f330295b..000000000 --- a/mainline/alpine/20-envsubst-on-templates.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/sh - -set -e - -ME=$(basename $0) - -auto_envsubst() { - local template_dir="${NGINX_ENVSUBST_TEMPLATE_DIR:-/etc/nginx/templates}" - local suffix="${NGINX_ENVSUBST_TEMPLATE_SUFFIX:-.template}" - local output_dir="${NGINX_ENVSUBST_OUTPUT_DIR:-/etc/nginx/conf.d}" - - local template defined_envs relative_path output_path subdir - defined_envs=$(printf '${%s} ' $(env | cut -d= -f1)) - [ -d "$template_dir" ] || return 0 - if [ ! -w "$output_dir" ]; then - echo >&3 "$ME: ERROR: $template_dir exists, but $output_dir is not writable" - return 0 - fi - find "$template_dir" -follow -type f -name "*$suffix" -print | while read -r template; do - relative_path="${template#$template_dir/}" - output_path="$output_dir/${relative_path%$suffix}" - subdir=$(dirname "$relative_path") - # create a subdirectory where the template file exists - mkdir -p "$output_dir/$subdir" - echo >&3 "$ME: Running envsubst on $template to $output_path" - envsubst "$defined_envs" < "$template" > "$output_path" - done -} - -auto_envsubst - -exit 0 diff --git a/mainline/alpine/Dockerfile b/mainline/alpine/Dockerfile index 75aebbe95..ff89c3b25 100644 --- a/mainline/alpine/Dockerfile +++ b/mainline/alpine/Dockerfile @@ -3,25 +3,19 @@ # # PLEASE DO NOT EDIT IT DIRECTLY. # -FROM alpine:3.16 +FROM nginx:1.29.3-alpine-slim -LABEL maintainer="NGINX Docker Maintainers " - -ENV NGINX_VERSION 1.23.0 -ENV NJS_VERSION 0.7.5 -ENV PKG_RELEASE 1 +ENV NJS_VERSION 0.9.4 +ENV NJS_RELEASE 1 RUN set -x \ -# create nginx user/group first, to be consistent throughout docker variants - && addgroup -g 101 -S nginx \ - && adduser -S -D -H -u 101 -h /var/cache/nginx -s /sbin/nologin -G nginx -g nginx nginx \ && apkArch="$(cat /etc/apk/arch)" \ && nginxPackages=" \ nginx=${NGINX_VERSION}-r${PKG_RELEASE} \ - nginx-module-xslt=${NGINX_VERSION}-r${PKG_RELEASE} \ - nginx-module-geoip=${NGINX_VERSION}-r${PKG_RELEASE} \ - nginx-module-image-filter=${NGINX_VERSION}-r${PKG_RELEASE} \ - nginx-module-njs=${NGINX_VERSION}.${NJS_VERSION}-r${PKG_RELEASE} \ + nginx-module-xslt=${NGINX_VERSION}-r${DYNPKG_RELEASE} \ + nginx-module-geoip=${NGINX_VERSION}-r${DYNPKG_RELEASE} \ + nginx-module-image-filter=${NGINX_VERSION}-r${DYNPKG_RELEASE} \ + nginx-module-njs=${NGINX_VERSION}.${NJS_VERSION}-r${NJS_RELEASE} \ " \ # install prerequisites for public key and pkg-oss checks && apk add --no-cache --virtual .checksum-deps \ @@ -29,17 +23,7 @@ RUN set -x \ && case "$apkArch" in \ x86_64|aarch64) \ # arches officially built by upstream - set -x \ - && KEY_SHA512="e7fa8303923d9b95db37a77ad46c68fd4755ff935d0a534d26eba83de193c76166c68bfe7f65471bf8881004ef4aa6df3e34689c305662750c0172fca5d8552a *stdin" \ - && wget -O /tmp/nginx_signing.rsa.pub https://nginx.org/keys/nginx_signing.rsa.pub \ - && if [ "$(openssl rsa -pubin -in /tmp/nginx_signing.rsa.pub -text -noout | openssl sha512 -r)" = "$KEY_SHA512" ]; then \ - echo "key verification succeeded!"; \ - mv /tmp/nginx_signing.rsa.pub /etc/apk/keys/; \ - else \ - echo "key verification failed!"; \ - exit 1; \ - fi \ - && apk add -X "https://nginx.org/packages/mainline/alpine/v$(egrep -o '^[0-9]+\.[0-9]+' /etc/alpine-release)/main" --no-cache $nginxPackages \ + apk add -X "https://nginx.org/packages/mainline/alpine/v$(egrep -o '^[0-9]+\.[0-9]+' /etc/alpine-release)/main" --no-cache $nginxPackages \ ;; \ *) \ # we're on an architecture upstream doesn't officially build for @@ -58,16 +42,16 @@ RUN set -x \ libxslt-dev \ gd-dev \ geoip-dev \ - perl-dev \ libedit-dev \ bash \ alpine-sdk \ findutils \ + curl \ && su nobody -s /bin/sh -c " \ export HOME=${tempDir} \ && cd ${tempDir} \ - && curl -f -O https://hg.nginx.org/pkg-oss/archive/${NGINX_VERSION}-${PKG_RELEASE}.tar.gz \ - && PKGOSSCHECKSUM=\"678b1e9ab34777f1a1a1a8717aff0dfa08cc187cf2cf140c084d23205f3ba3af97805e72ebbed49dd7bfcb23bbeca982b150fff5c2a6c96f161ed9085101f1a4 *${NGINX_VERSION}-${PKG_RELEASE}.tar.gz\" \ + && curl -f -L -O https://github.com/nginx/pkg-oss/archive/${NGINX_VERSION}-${PKG_RELEASE}.tar.gz \ + && PKGOSSCHECKSUM=\"249858446828ace0c81ea3e057135aa368f3dab83430cf867bb9fc32598948f29c4bd50908491da704536af1106aa87553f6a76cc126c6833dc9b14dd00564b8 *${NGINX_VERSION}-${PKG_RELEASE}.tar.gz\" \ && if [ \"\$(openssl sha512 -r ${NGINX_VERSION}-${PKG_RELEASE}.tar.gz)\" = \"\$PKGOSSCHECKSUM\" ]; then \ echo \"pkg-oss tarball checksum verification succeeded!\"; \ else \ @@ -77,57 +61,19 @@ RUN set -x \ && tar xzvf ${NGINX_VERSION}-${PKG_RELEASE}.tar.gz \ && cd pkg-oss-${NGINX_VERSION}-${PKG_RELEASE} \ && cd alpine \ - && make all \ - && apk index -o ${tempDir}/packages/alpine/${apkArch}/APKINDEX.tar.gz ${tempDir}/packages/alpine/${apkArch}/*.apk \ + && make module-geoip module-image-filter module-njs module-xslt \ + && apk index --allow-untrusted -o ${tempDir}/packages/alpine/${apkArch}/APKINDEX.tar.gz ${tempDir}/packages/alpine/${apkArch}/*.apk \ && abuild-sign -k ${tempDir}/.abuild/abuild-key.rsa ${tempDir}/packages/alpine/${apkArch}/APKINDEX.tar.gz \ " \ && cp ${tempDir}/.abuild/abuild-key.rsa.pub /etc/apk/keys/ \ - && apk del .build-deps \ + && apk del --no-network .build-deps \ && apk add -X ${tempDir}/packages/alpine/ --no-cache $nginxPackages \ ;; \ esac \ # remove checksum deps - && apk del .checksum-deps \ + && apk del --no-network .checksum-deps \ # if we have leftovers from building, let's purge them (including extra, unnecessary build deps) && if [ -n "$tempDir" ]; then rm -rf "$tempDir"; fi \ - && if [ -n "/etc/apk/keys/abuild-key.rsa.pub" ]; then rm -f /etc/apk/keys/abuild-key.rsa.pub; fi \ - && if [ -n "/etc/apk/keys/nginx_signing.rsa.pub" ]; then rm -f /etc/apk/keys/nginx_signing.rsa.pub; fi \ -# Bring in gettext so we can get `envsubst`, then throw -# the rest away. To do this, we need to install `gettext` -# then move `envsubst` out of the way so `gettext` can -# be deleted completely, then move `envsubst` back. - && apk add --no-cache --virtual .gettext gettext \ - && mv /usr/bin/envsubst /tmp/ \ - \ - && runDeps="$( \ - scanelf --needed --nobanner /tmp/envsubst \ - | awk '{ gsub(/,/, "\nso:", $2); print "so:" $2 }' \ - | sort -u \ - | xargs -r apk info --installed \ - | sort -u \ - )" \ - && apk add --no-cache $runDeps \ - && apk del .gettext \ - && mv /tmp/envsubst /usr/local/bin/ \ -# Bring in tzdata so users could set the timezones through the environment -# variables - && apk add --no-cache tzdata \ + && if [ -f "/etc/apk/keys/abuild-key.rsa.pub" ]; then rm -f /etc/apk/keys/abuild-key.rsa.pub; fi \ # Bring in curl and ca-certificates to make registering on DNS SD easier - && apk add --no-cache curl ca-certificates \ -# forward request and error logs to docker log collector - && ln -sf /dev/stdout /var/log/nginx/access.log \ - && ln -sf /dev/stderr /var/log/nginx/error.log \ -# create a docker-entrypoint.d directory - && mkdir /docker-entrypoint.d - -COPY docker-entrypoint.sh / -COPY 10-listen-on-ipv6-by-default.sh /docker-entrypoint.d -COPY 20-envsubst-on-templates.sh /docker-entrypoint.d -COPY 30-tune-worker-processes.sh /docker-entrypoint.d -ENTRYPOINT ["/docker-entrypoint.sh"] - -EXPOSE 80 - -STOPSIGNAL SIGQUIT - -CMD ["nginx", "-g", "daemon off;"] + && apk add --no-cache curl ca-certificates diff --git a/mainline/alpine/docker-entrypoint.sh b/mainline/alpine/docker-entrypoint.sh deleted file mode 100755 index 72d5cd94e..000000000 --- a/mainline/alpine/docker-entrypoint.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh -# vim:sw=4:ts=4:et - -set -e - -if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then - exec 3>&1 -else - exec 3>/dev/null -fi - -if [ "$1" = "nginx" -o "$1" = "nginx-debug" ]; then - if /usr/bin/find "/docker-entrypoint.d/" -mindepth 1 -maxdepth 1 -type f -print -quit 2>/dev/null | read v; then - echo >&3 "$0: /docker-entrypoint.d/ is not empty, will attempt to perform configuration" - - echo >&3 "$0: Looking for shell scripts in /docker-entrypoint.d/" - find "/docker-entrypoint.d/" -follow -type f -print | sort -V | while read -r f; do - case "$f" in - *.sh) - if [ -x "$f" ]; then - echo >&3 "$0: Launching $f"; - "$f" - else - # warn on shell scripts without exec bit - echo >&3 "$0: Ignoring $f, not executable"; - fi - ;; - *) echo >&3 "$0: Ignoring $f";; - esac - done - - echo >&3 "$0: Configuration complete; ready for start up" - else - echo >&3 "$0: No files found in /docker-entrypoint.d/, skipping configuration" - fi -fi - -exec "$@" diff --git a/mainline/debian-otel/Dockerfile b/mainline/debian-otel/Dockerfile new file mode 100644 index 000000000..da68ae7c9 --- /dev/null +++ b/mainline/debian-otel/Dockerfile @@ -0,0 +1,100 @@ +# +# NOTE: THIS DOCKERFILE IS GENERATED VIA "update.sh" +# +# PLEASE DO NOT EDIT IT DIRECTLY. +# +FROM nginx:1.29.3 + +ENV OTEL_VERSION 0.1.2 + +RUN set -x; \ + NGINX_GPGKEY_PATH=/etc/apt/keyrings/nginx-archive-keyring.gpg; \ + dpkgArch="$(dpkg --print-architecture)" \ + && nginxPackages=" \ + nginx=${NGINX_VERSION}-${PKG_RELEASE} \ + nginx-module-xslt=${NGINX_VERSION}-${DYNPKG_RELEASE} \ + nginx-module-geoip=${NGINX_VERSION}-${DYNPKG_RELEASE} \ + nginx-module-image-filter=${NGINX_VERSION}-${DYNPKG_RELEASE} \ + nginx-module-njs=${NGINX_VERSION}+${NJS_VERSION}-${NJS_RELEASE} \ + nginx-module-otel=${NGINX_VERSION}+${OTEL_VERSION}-${PKG_RELEASE} \ + " \ + && case "$dpkgArch" in \ + amd64|arm64) \ +# arches officialy built by upstream + echo "deb [signed-by=$NGINX_GPGKEY_PATH] https://nginx.org/packages/mainline/debian/ trixie nginx" >> /etc/apt/sources.list.d/nginx.list \ + && apt-get update \ + ;; \ + *) \ +# we're on an architecture upstream doesn't officially build for +# let's build binaries from the published packaging sources +# new directory for storing sources and .deb files + tempDir="$(mktemp -d)" \ + && chmod 777 "$tempDir" \ +# (777 to ensure APT's "_apt" user can access it too) + \ +# save list of currently-installed packages so build dependencies can be cleanly removed later + && savedAptMark="$(apt-mark showmanual)" \ + \ +# build .deb files from upstream's packaging sources + && apt-get update \ + && apt-get install --no-install-recommends --no-install-suggests -y \ + curl \ + devscripts \ + equivs \ + git \ + libxml2-utils \ + lsb-release \ + xsltproc \ + && ( \ + cd "$tempDir" \ + && REVISION="${NGINX_VERSION}-${PKG_RELEASE}" \ + && REVISION=${REVISION%~*} \ + && curl -f -L -O https://github.com/nginx/pkg-oss/archive/${REVISION}.tar.gz \ + && PKGOSSCHECKSUM="249858446828ace0c81ea3e057135aa368f3dab83430cf867bb9fc32598948f29c4bd50908491da704536af1106aa87553f6a76cc126c6833dc9b14dd00564b8 *${REVISION}.tar.gz" \ + && if [ "$(openssl sha512 -r ${REVISION}.tar.gz)" = "$PKGOSSCHECKSUM" ]; then \ + echo "pkg-oss tarball checksum verification succeeded!"; \ + else \ + echo "pkg-oss tarball checksum verification failed!"; \ + exit 1; \ + fi \ + && tar xzvf ${REVISION}.tar.gz \ + && cd pkg-oss-${REVISION} \ + && cd debian \ + && for target in module-otel; do \ + make rules-$target; \ + mk-build-deps --install --tool="apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends --yes" \ + debuild-$target/nginx-$NGINX_VERSION/debian/control; \ + done \ + && make module-otel \ + ) \ +# we don't remove APT lists here because they get re-downloaded and removed later + \ +# reset apt-mark's "manual" list so that "purge --auto-remove" will remove all build dependencies +# (which is done after we install the built packages so we don't have to redownload any overlapping dependencies) + && apt-mark showmanual | xargs apt-mark auto > /dev/null \ + && { [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; } \ + \ +# create a temporary local APT repo to install from (so that dependency resolution can be handled by APT, as it should be) + && ls -lAFh "$tempDir" \ + && ( cd "$tempDir" && dpkg-scanpackages . > Packages ) \ + && grep '^Package: ' "$tempDir/Packages" \ + && echo "deb [ trusted=yes ] file://$tempDir ./" > /etc/apt/sources.list.d/temp.list \ +# work around the following APT issue by using "Acquire::GzipIndexes=false" (overriding "/etc/apt/apt.conf.d/docker-gzip-indexes") +# Could not open file /var/lib/apt/lists/partial/_tmp_tmp.ODWljpQfkE_._Packages - open (13: Permission denied) +# ... +# E: Failed to fetch store:/var/lib/apt/lists/partial/_tmp_tmp.ODWljpQfkE_._Packages Could not open file /var/lib/apt/lists/partial/_tmp_tmp.ODWljpQfkE_._Packages - open (13: Permission denied) + && apt-get -o Acquire::GzipIndexes=false update \ + ;; \ + esac \ + \ + && apt-get install --no-install-recommends --no-install-suggests -y \ + $nginxPackages \ + gettext-base \ + curl \ + && apt-get remove --purge --auto-remove -y && rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/nginx.list \ + \ +# if we have leftovers from building, let's purge them (including extra, unnecessary build deps) + && if [ -n "$tempDir" ]; then \ + apt-get purge -y --auto-remove \ + && rm -rf "$tempDir" /etc/apt/sources.list.d/temp.list; \ + fi diff --git a/mainline/debian-perl/10-listen-on-ipv6-by-default.sh b/mainline/debian-perl/10-listen-on-ipv6-by-default.sh deleted file mode 100755 index 9585152ba..000000000 --- a/mainline/debian-perl/10-listen-on-ipv6-by-default.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/bin/sh -# vim:sw=4:ts=4:et - -set -e - -ME=$(basename $0) -DEFAULT_CONF_FILE="etc/nginx/conf.d/default.conf" - -# check if we have ipv6 available -if [ ! -f "/proc/net/if_inet6" ]; then - echo >&3 "$ME: info: ipv6 not available" - exit 0 -fi - -if [ ! -f "/$DEFAULT_CONF_FILE" ]; then - echo >&3 "$ME: info: /$DEFAULT_CONF_FILE is not a file or does not exist" - exit 0 -fi - -# check if the file can be modified, e.g. not on a r/o filesystem -touch /$DEFAULT_CONF_FILE 2>/dev/null || { echo >&3 "$ME: info: can not modify /$DEFAULT_CONF_FILE (read-only file system?)"; exit 0; } - -# check if the file is already modified, e.g. on a container restart -grep -q "listen \[::]\:80;" /$DEFAULT_CONF_FILE && { echo >&3 "$ME: info: IPv6 listen already enabled"; exit 0; } - -if [ -f "/etc/os-release" ]; then - . /etc/os-release -else - echo >&3 "$ME: info: can not guess the operating system" - exit 0 -fi - -echo >&3 "$ME: info: Getting the checksum of /$DEFAULT_CONF_FILE" - -case "$ID" in - "debian") - CHECKSUM=$(dpkg-query --show --showformat='${Conffiles}\n' nginx | grep $DEFAULT_CONF_FILE | cut -d' ' -f 3) - echo "$CHECKSUM /$DEFAULT_CONF_FILE" | md5sum -c - >/dev/null 2>&1 || { - echo >&3 "$ME: info: /$DEFAULT_CONF_FILE differs from the packaged version" - exit 0 - } - ;; - "alpine") - CHECKSUM=$(apk manifest nginx 2>/dev/null| grep $DEFAULT_CONF_FILE | cut -d' ' -f 1 | cut -d ':' -f 2) - echo "$CHECKSUM /$DEFAULT_CONF_FILE" | sha1sum -c - >/dev/null 2>&1 || { - echo >&3 "$ME: info: /$DEFAULT_CONF_FILE differs from the packaged version" - exit 0 - } - ;; - *) - echo >&3 "$ME: info: Unsupported distribution" - exit 0 - ;; -esac - -# enable ipv6 on default.conf listen sockets -sed -i -E 's,listen 80;,listen 80;\n listen [::]:80;,' /$DEFAULT_CONF_FILE - -echo >&3 "$ME: info: Enabled listen on IPv6 in /$DEFAULT_CONF_FILE" - -exit 0 diff --git a/mainline/debian-perl/20-envsubst-on-templates.sh b/mainline/debian-perl/20-envsubst-on-templates.sh deleted file mode 100755 index 4f330295b..000000000 --- a/mainline/debian-perl/20-envsubst-on-templates.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/sh - -set -e - -ME=$(basename $0) - -auto_envsubst() { - local template_dir="${NGINX_ENVSUBST_TEMPLATE_DIR:-/etc/nginx/templates}" - local suffix="${NGINX_ENVSUBST_TEMPLATE_SUFFIX:-.template}" - local output_dir="${NGINX_ENVSUBST_OUTPUT_DIR:-/etc/nginx/conf.d}" - - local template defined_envs relative_path output_path subdir - defined_envs=$(printf '${%s} ' $(env | cut -d= -f1)) - [ -d "$template_dir" ] || return 0 - if [ ! -w "$output_dir" ]; then - echo >&3 "$ME: ERROR: $template_dir exists, but $output_dir is not writable" - return 0 - fi - find "$template_dir" -follow -type f -name "*$suffix" -print | while read -r template; do - relative_path="${template#$template_dir/}" - output_path="$output_dir/${relative_path%$suffix}" - subdir=$(dirname "$relative_path") - # create a subdirectory where the template file exists - mkdir -p "$output_dir/$subdir" - echo >&3 "$ME: Running envsubst on $template to $output_path" - envsubst "$defined_envs" < "$template" > "$output_path" - done -} - -auto_envsubst - -exit 0 diff --git a/mainline/debian-perl/Dockerfile b/mainline/debian-perl/Dockerfile index a0c1781b6..ef0ad258a 100644 --- a/mainline/debian-perl/Dockerfile +++ b/mainline/debian-perl/Dockerfile @@ -3,67 +3,67 @@ # # PLEASE DO NOT EDIT IT DIRECTLY. # -FROM debian:bullseye-slim +FROM nginx:1.29.3 -LABEL maintainer="NGINX Docker Maintainers " - -ENV NGINX_VERSION 1.23.0 -ENV NJS_VERSION 0.7.5 -ENV PKG_RELEASE 1~bullseye - -RUN set -x \ -# create nginx user/group first, to be consistent throughout docker variants - && addgroup --system --gid 101 nginx \ - && adduser --system --disabled-login --ingroup nginx --no-create-home --home /nonexistent --gecos "nginx user" --shell /bin/false --uid 101 nginx \ - && apt-get update \ - && apt-get install --no-install-recommends --no-install-suggests -y gnupg1 ca-certificates \ - && \ - NGINX_GPGKEY=573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62; \ - found=''; \ - for server in \ - hkp://keyserver.ubuntu.com:80 \ - pgp.mit.edu \ - ; do \ - echo "Fetching GPG key $NGINX_GPGKEY from $server"; \ - apt-key adv --keyserver "$server" --keyserver-options timeout=10 --recv-keys "$NGINX_GPGKEY" && found=yes && break; \ - done; \ - test -z "$found" && echo >&2 "error: failed to fetch GPG key $NGINX_GPGKEY" && exit 1; \ - apt-get remove --purge --auto-remove -y gnupg1 && rm -rf /var/lib/apt/lists/* \ - && dpkgArch="$(dpkg --print-architecture)" \ +RUN set -x; \ + NGINX_GPGKEY_PATH=/etc/apt/keyrings/nginx-archive-keyring.gpg; \ + dpkgArch="$(dpkg --print-architecture)" \ && nginxPackages=" \ nginx=${NGINX_VERSION}-${PKG_RELEASE} \ - nginx-module-xslt=${NGINX_VERSION}-${PKG_RELEASE} \ - nginx-module-geoip=${NGINX_VERSION}-${PKG_RELEASE} \ - nginx-module-image-filter=${NGINX_VERSION}-${PKG_RELEASE} \ - nginx-module-perl=${NGINX_VERSION}-${PKG_RELEASE} \ - nginx-module-njs=${NGINX_VERSION}+${NJS_VERSION}-${PKG_RELEASE} \ + nginx-module-xslt=${NGINX_VERSION}-${DYNPKG_RELEASE} \ + nginx-module-geoip=${NGINX_VERSION}-${DYNPKG_RELEASE} \ + nginx-module-image-filter=${NGINX_VERSION}-${DYNPKG_RELEASE} \ + nginx-module-perl=${NGINX_VERSION}-${DYNPKG_RELEASE} \ + nginx-module-njs=${NGINX_VERSION}+${NJS_VERSION}-${NJS_RELEASE} \ " \ && case "$dpkgArch" in \ amd64|arm64) \ # arches officialy built by upstream - echo "deb https://nginx.org/packages/mainline/debian/ bullseye nginx" >> /etc/apt/sources.list.d/nginx.list \ + echo "deb [signed-by=$NGINX_GPGKEY_PATH] https://nginx.org/packages/mainline/debian/ trixie nginx" >> /etc/apt/sources.list.d/nginx.list \ && apt-get update \ ;; \ *) \ # we're on an architecture upstream doesn't officially build for -# let's build binaries from the published source packages - echo "deb-src https://nginx.org/packages/mainline/debian/ bullseye nginx" >> /etc/apt/sources.list.d/nginx.list \ - \ +# let's build binaries from the published packaging sources # new directory for storing sources and .deb files - && tempDir="$(mktemp -d)" \ + tempDir="$(mktemp -d)" \ && chmod 777 "$tempDir" \ # (777 to ensure APT's "_apt" user can access it too) \ # save list of currently-installed packages so build dependencies can be cleanly removed later && savedAptMark="$(apt-mark showmanual)" \ \ -# build .deb files from upstream's source packages (which are verified by apt-get) +# build .deb files from upstream's packaging sources && apt-get update \ - && apt-get build-dep -y $nginxPackages \ + && apt-get install --no-install-recommends --no-install-suggests -y \ + curl \ + devscripts \ + equivs \ + git \ + libxml2-utils \ + lsb-release \ + xsltproc \ && ( \ cd "$tempDir" \ - && DEB_BUILD_OPTIONS="nocheck parallel=$(nproc)" \ - apt-get source --compile $nginxPackages \ + && REVISION="${NGINX_VERSION}-${PKG_RELEASE}" \ + && REVISION=${REVISION%~*} \ + && curl -f -L -O https://github.com/nginx/pkg-oss/archive/${REVISION}.tar.gz \ + && PKGOSSCHECKSUM="249858446828ace0c81ea3e057135aa368f3dab83430cf867bb9fc32598948f29c4bd50908491da704536af1106aa87553f6a76cc126c6833dc9b14dd00564b8 *${REVISION}.tar.gz" \ + && if [ "$(openssl sha512 -r ${REVISION}.tar.gz)" = "$PKGOSSCHECKSUM" ]; then \ + echo "pkg-oss tarball checksum verification succeeded!"; \ + else \ + echo "pkg-oss tarball checksum verification failed!"; \ + exit 1; \ + fi \ + && tar xzvf ${REVISION}.tar.gz \ + && cd pkg-oss-${REVISION} \ + && cd debian \ + && for target in module-perl; do \ + make rules-$target; \ + mk-build-deps --install --tool="apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends --yes" \ + debuild-$target/nginx-$NGINX_VERSION/debian/control; \ + done \ + && make module-perl \ ) \ # we don't remove APT lists here because they get re-downloaded and removed later \ @@ -95,21 +95,4 @@ RUN set -x \ && if [ -n "$tempDir" ]; then \ apt-get purge -y --auto-remove \ && rm -rf "$tempDir" /etc/apt/sources.list.d/temp.list; \ - fi \ -# forward request and error logs to docker log collector - && ln -sf /dev/stdout /var/log/nginx/access.log \ - && ln -sf /dev/stderr /var/log/nginx/error.log \ -# create a docker-entrypoint.d directory - && mkdir /docker-entrypoint.d - -COPY docker-entrypoint.sh / -COPY 10-listen-on-ipv6-by-default.sh /docker-entrypoint.d -COPY 20-envsubst-on-templates.sh /docker-entrypoint.d -COPY 30-tune-worker-processes.sh /docker-entrypoint.d -ENTRYPOINT ["/docker-entrypoint.sh"] - -EXPOSE 80 - -STOPSIGNAL SIGQUIT - -CMD ["nginx", "-g", "daemon off;"] + fi diff --git a/mainline/debian-perl/docker-entrypoint.sh b/mainline/debian-perl/docker-entrypoint.sh deleted file mode 100755 index 72d5cd94e..000000000 --- a/mainline/debian-perl/docker-entrypoint.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh -# vim:sw=4:ts=4:et - -set -e - -if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then - exec 3>&1 -else - exec 3>/dev/null -fi - -if [ "$1" = "nginx" -o "$1" = "nginx-debug" ]; then - if /usr/bin/find "/docker-entrypoint.d/" -mindepth 1 -maxdepth 1 -type f -print -quit 2>/dev/null | read v; then - echo >&3 "$0: /docker-entrypoint.d/ is not empty, will attempt to perform configuration" - - echo >&3 "$0: Looking for shell scripts in /docker-entrypoint.d/" - find "/docker-entrypoint.d/" -follow -type f -print | sort -V | while read -r f; do - case "$f" in - *.sh) - if [ -x "$f" ]; then - echo >&3 "$0: Launching $f"; - "$f" - else - # warn on shell scripts without exec bit - echo >&3 "$0: Ignoring $f, not executable"; - fi - ;; - *) echo >&3 "$0: Ignoring $f";; - esac - done - - echo >&3 "$0: Configuration complete; ready for start up" - else - echo >&3 "$0: No files found in /docker-entrypoint.d/, skipping configuration" - fi -fi - -exec "$@" diff --git a/mainline/debian/10-listen-on-ipv6-by-default.sh b/mainline/debian/10-listen-on-ipv6-by-default.sh index 9585152ba..61a901dee 100755 --- a/mainline/debian/10-listen-on-ipv6-by-default.sh +++ b/mainline/debian/10-listen-on-ipv6-by-default.sh @@ -3,52 +3,58 @@ set -e -ME=$(basename $0) +entrypoint_log() { + if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then + echo "$@" + fi +} + +ME=$(basename "$0") DEFAULT_CONF_FILE="etc/nginx/conf.d/default.conf" # check if we have ipv6 available if [ ! -f "/proc/net/if_inet6" ]; then - echo >&3 "$ME: info: ipv6 not available" + entrypoint_log "$ME: info: ipv6 not available" exit 0 fi if [ ! -f "/$DEFAULT_CONF_FILE" ]; then - echo >&3 "$ME: info: /$DEFAULT_CONF_FILE is not a file or does not exist" + entrypoint_log "$ME: info: /$DEFAULT_CONF_FILE is not a file or does not exist" exit 0 fi # check if the file can be modified, e.g. not on a r/o filesystem -touch /$DEFAULT_CONF_FILE 2>/dev/null || { echo >&3 "$ME: info: can not modify /$DEFAULT_CONF_FILE (read-only file system?)"; exit 0; } +touch /$DEFAULT_CONF_FILE 2>/dev/null || { entrypoint_log "$ME: info: can not modify /$DEFAULT_CONF_FILE (read-only file system?)"; exit 0; } # check if the file is already modified, e.g. on a container restart -grep -q "listen \[::]\:80;" /$DEFAULT_CONF_FILE && { echo >&3 "$ME: info: IPv6 listen already enabled"; exit 0; } +grep -q "listen \[::\]:80;" /$DEFAULT_CONF_FILE && { entrypoint_log "$ME: info: IPv6 listen already enabled"; exit 0; } if [ -f "/etc/os-release" ]; then . /etc/os-release else - echo >&3 "$ME: info: can not guess the operating system" + entrypoint_log "$ME: info: can not guess the operating system" exit 0 fi -echo >&3 "$ME: info: Getting the checksum of /$DEFAULT_CONF_FILE" +entrypoint_log "$ME: info: Getting the checksum of /$DEFAULT_CONF_FILE" case "$ID" in "debian") CHECKSUM=$(dpkg-query --show --showformat='${Conffiles}\n' nginx | grep $DEFAULT_CONF_FILE | cut -d' ' -f 3) echo "$CHECKSUM /$DEFAULT_CONF_FILE" | md5sum -c - >/dev/null 2>&1 || { - echo >&3 "$ME: info: /$DEFAULT_CONF_FILE differs from the packaged version" + entrypoint_log "$ME: info: /$DEFAULT_CONF_FILE differs from the packaged version" exit 0 } ;; "alpine") CHECKSUM=$(apk manifest nginx 2>/dev/null| grep $DEFAULT_CONF_FILE | cut -d' ' -f 1 | cut -d ':' -f 2) echo "$CHECKSUM /$DEFAULT_CONF_FILE" | sha1sum -c - >/dev/null 2>&1 || { - echo >&3 "$ME: info: /$DEFAULT_CONF_FILE differs from the packaged version" + entrypoint_log "$ME: info: /$DEFAULT_CONF_FILE differs from the packaged version" exit 0 } ;; *) - echo >&3 "$ME: info: Unsupported distribution" + entrypoint_log "$ME: info: Unsupported distribution" exit 0 ;; esac @@ -56,6 +62,6 @@ esac # enable ipv6 on default.conf listen sockets sed -i -E 's,listen 80;,listen 80;\n listen [::]:80;,' /$DEFAULT_CONF_FILE -echo >&3 "$ME: info: Enabled listen on IPv6 in /$DEFAULT_CONF_FILE" +entrypoint_log "$ME: info: Enabled listen on IPv6 in /$DEFAULT_CONF_FILE" exit 0 diff --git a/mainline/debian/15-local-resolvers.envsh b/mainline/debian/15-local-resolvers.envsh new file mode 100755 index 000000000..e830ddacd --- /dev/null +++ b/mainline/debian/15-local-resolvers.envsh @@ -0,0 +1,15 @@ +#!/bin/sh +# vim:sw=2:ts=2:sts=2:et + +set -eu + +LC_ALL=C +PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin + +[ "${NGINX_ENTRYPOINT_LOCAL_RESOLVERS:-}" ] || return 0 + +NGINX_LOCAL_RESOLVERS=$(awk 'BEGIN{ORS=" "} $1=="nameserver" {if ($2 ~ ":") {print "["$2"]"} else {print $2}}' /etc/resolv.conf) + +NGINX_LOCAL_RESOLVERS="${NGINX_LOCAL_RESOLVERS% }" + +export NGINX_LOCAL_RESOLVERS diff --git a/mainline/debian/20-envsubst-on-templates.sh b/mainline/debian/20-envsubst-on-templates.sh index 4f330295b..3804165c9 100755 --- a/mainline/debian/20-envsubst-on-templates.sh +++ b/mainline/debian/20-envsubst-on-templates.sh @@ -2,29 +2,75 @@ set -e -ME=$(basename $0) +ME=$(basename "$0") + +entrypoint_log() { + if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then + echo "$@" + fi +} + +add_stream_block() { + local conffile="/etc/nginx/nginx.conf" + + if grep -q -E "\s*stream\s*\{" "$conffile"; then + entrypoint_log "$ME: $conffile contains a stream block; include $stream_output_dir/*.conf to enable stream templates" + else + # check if the file can be modified, e.g. not on a r/o filesystem + touch "$conffile" 2>/dev/null || { entrypoint_log "$ME: info: can not modify $conffile (read-only file system?)"; exit 0; } + entrypoint_log "$ME: Appending stream block to $conffile to include $stream_output_dir/*.conf" + cat << END >> "$conffile" +# added by "$ME" on "$(date)" +stream { + include $stream_output_dir/*.conf; +} +END + fi +} auto_envsubst() { local template_dir="${NGINX_ENVSUBST_TEMPLATE_DIR:-/etc/nginx/templates}" local suffix="${NGINX_ENVSUBST_TEMPLATE_SUFFIX:-.template}" local output_dir="${NGINX_ENVSUBST_OUTPUT_DIR:-/etc/nginx/conf.d}" + local stream_suffix="${NGINX_ENVSUBST_STREAM_TEMPLATE_SUFFIX:-.stream-template}" + local stream_output_dir="${NGINX_ENVSUBST_STREAM_OUTPUT_DIR:-/etc/nginx/stream-conf.d}" + local filter="${NGINX_ENVSUBST_FILTER:-}" local template defined_envs relative_path output_path subdir - defined_envs=$(printf '${%s} ' $(env | cut -d= -f1)) + defined_envs=$(printf '${%s} ' $(awk "END { for (name in ENVIRON) { print ( name ~ /${filter}/ ) ? name : \"\" } }" < /dev/null )) [ -d "$template_dir" ] || return 0 if [ ! -w "$output_dir" ]; then - echo >&3 "$ME: ERROR: $template_dir exists, but $output_dir is not writable" + entrypoint_log "$ME: ERROR: $template_dir exists, but $output_dir is not writable" return 0 fi find "$template_dir" -follow -type f -name "*$suffix" -print | while read -r template; do - relative_path="${template#$template_dir/}" - output_path="$output_dir/${relative_path%$suffix}" + relative_path="${template#"$template_dir/"}" + output_path="$output_dir/${relative_path%"$suffix"}" subdir=$(dirname "$relative_path") # create a subdirectory where the template file exists mkdir -p "$output_dir/$subdir" - echo >&3 "$ME: Running envsubst on $template to $output_path" + entrypoint_log "$ME: Running envsubst on $template to $output_path" envsubst "$defined_envs" < "$template" > "$output_path" done + + # Print the first file with the stream suffix, this will be false if there are none + if test -n "$(find "$template_dir" -name "*$stream_suffix" -print -quit)"; then + mkdir -p "$stream_output_dir" + if [ ! -w "$stream_output_dir" ]; then + entrypoint_log "$ME: ERROR: $template_dir exists, but $stream_output_dir is not writable" + return 0 + fi + add_stream_block + find "$template_dir" -follow -type f -name "*$stream_suffix" -print | while read -r template; do + relative_path="${template#"$template_dir/"}" + output_path="$stream_output_dir/${relative_path%"$stream_suffix"}" + subdir=$(dirname "$relative_path") + # create a subdirectory where the template file exists + mkdir -p "$stream_output_dir/$subdir" + entrypoint_log "$ME: Running envsubst on $template to $output_path" + envsubst "$defined_envs" < "$template" > "$output_path" + done + fi } auto_envsubst diff --git a/mainline/debian/30-tune-worker-processes.sh b/mainline/debian/30-tune-worker-processes.sh index 565058715..defb994f3 100755 --- a/mainline/debian/30-tune-worker-processes.sh +++ b/mainline/debian/30-tune-worker-processes.sh @@ -4,7 +4,7 @@ set -eu LC_ALL=C -ME=$( basename "$0" ) +ME=$(basename "$0") PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin [ "${NGINX_ENTRYPOINT_WORKER_PROCESSES_AUTOTUNE:-}" ] || exit 0 @@ -158,7 +158,7 @@ __EOF__ "/") foundroot="${found##* }$mountpoint" ;; - "$mountpoint") + "$mountpoint" | /../*) foundroot="${found##* }" ;; esac diff --git a/mainline/debian/Dockerfile b/mainline/debian/Dockerfile index 4be092e9d..27b4e1312 100644 --- a/mainline/debian/Dockerfile +++ b/mainline/debian/Dockerfile @@ -3,66 +3,96 @@ # # PLEASE DO NOT EDIT IT DIRECTLY. # -FROM debian:bullseye-slim +FROM debian:trixie-slim LABEL maintainer="NGINX Docker Maintainers " -ENV NGINX_VERSION 1.23.0 -ENV NJS_VERSION 0.7.5 -ENV PKG_RELEASE 1~bullseye +ENV NGINX_VERSION 1.29.3 +ENV NJS_VERSION 0.9.4 +ENV NJS_RELEASE 1~trixie +ENV PKG_RELEASE 1~trixie +ENV DYNPKG_RELEASE 1~trixie RUN set -x \ # create nginx user/group first, to be consistent throughout docker variants - && addgroup --system --gid 101 nginx \ - && adduser --system --disabled-login --ingroup nginx --no-create-home --home /nonexistent --gecos "nginx user" --shell /bin/false --uid 101 nginx \ + && groupadd --system --gid 101 nginx \ + && useradd --system --gid nginx --no-create-home --home /nonexistent --comment "nginx user" --shell /bin/false --uid 101 nginx \ && apt-get update \ && apt-get install --no-install-recommends --no-install-suggests -y gnupg1 ca-certificates \ && \ - NGINX_GPGKEY=573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62; \ + NGINX_GPGKEYS="573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 8540A6F18833A80E9C1653A42FD21310B49F6B46 9E9BE90EACBCDE69FE9B204CBCDCD8A38D88A2B3"; \ + NGINX_GPGKEY_PATH=/etc/apt/keyrings/nginx-archive-keyring.gpg; \ + export GNUPGHOME="$(mktemp -d)"; \ found=''; \ + for NGINX_GPGKEY in $NGINX_GPGKEYS; do \ for server in \ hkp://keyserver.ubuntu.com:80 \ pgp.mit.edu \ ; do \ echo "Fetching GPG key $NGINX_GPGKEY from $server"; \ - apt-key adv --keyserver "$server" --keyserver-options timeout=10 --recv-keys "$NGINX_GPGKEY" && found=yes && break; \ + gpg1 --batch --keyserver "$server" --keyserver-options timeout=10 --recv-keys "$NGINX_GPGKEY" && found=yes && break; \ done; \ test -z "$found" && echo >&2 "error: failed to fetch GPG key $NGINX_GPGKEY" && exit 1; \ + done; \ + gpg1 --batch --export $NGINX_GPGKEYS > "$NGINX_GPGKEY_PATH" ; \ + rm -rf "$GNUPGHOME"; \ apt-get remove --purge --auto-remove -y gnupg1 && rm -rf /var/lib/apt/lists/* \ && dpkgArch="$(dpkg --print-architecture)" \ && nginxPackages=" \ nginx=${NGINX_VERSION}-${PKG_RELEASE} \ - nginx-module-xslt=${NGINX_VERSION}-${PKG_RELEASE} \ - nginx-module-geoip=${NGINX_VERSION}-${PKG_RELEASE} \ - nginx-module-image-filter=${NGINX_VERSION}-${PKG_RELEASE} \ - nginx-module-njs=${NGINX_VERSION}+${NJS_VERSION}-${PKG_RELEASE} \ + nginx-module-xslt=${NGINX_VERSION}-${DYNPKG_RELEASE} \ + nginx-module-geoip=${NGINX_VERSION}-${DYNPKG_RELEASE} \ + nginx-module-image-filter=${NGINX_VERSION}-${DYNPKG_RELEASE} \ + nginx-module-njs=${NGINX_VERSION}+${NJS_VERSION}-${NJS_RELEASE} \ " \ && case "$dpkgArch" in \ amd64|arm64) \ # arches officialy built by upstream - echo "deb https://nginx.org/packages/mainline/debian/ bullseye nginx" >> /etc/apt/sources.list.d/nginx.list \ + echo "deb [signed-by=$NGINX_GPGKEY_PATH] https://nginx.org/packages/mainline/debian/ trixie nginx" >> /etc/apt/sources.list.d/nginx.list \ && apt-get update \ ;; \ *) \ # we're on an architecture upstream doesn't officially build for -# let's build binaries from the published source packages - echo "deb-src https://nginx.org/packages/mainline/debian/ bullseye nginx" >> /etc/apt/sources.list.d/nginx.list \ - \ +# let's build binaries from the published packaging sources # new directory for storing sources and .deb files - && tempDir="$(mktemp -d)" \ + tempDir="$(mktemp -d)" \ && chmod 777 "$tempDir" \ # (777 to ensure APT's "_apt" user can access it too) \ # save list of currently-installed packages so build dependencies can be cleanly removed later && savedAptMark="$(apt-mark showmanual)" \ \ -# build .deb files from upstream's source packages (which are verified by apt-get) +# build .deb files from upstream's packaging sources && apt-get update \ - && apt-get build-dep -y $nginxPackages \ + && apt-get install --no-install-recommends --no-install-suggests -y \ + curl \ + devscripts \ + equivs \ + git \ + libxml2-utils \ + lsb-release \ + xsltproc \ && ( \ cd "$tempDir" \ - && DEB_BUILD_OPTIONS="nocheck parallel=$(nproc)" \ - apt-get source --compile $nginxPackages \ + && REVISION="${NGINX_VERSION}-${PKG_RELEASE}" \ + && REVISION=${REVISION%~*} \ + && curl -f -L -O https://github.com/nginx/pkg-oss/archive/${REVISION}.tar.gz \ + && PKGOSSCHECKSUM="249858446828ace0c81ea3e057135aa368f3dab83430cf867bb9fc32598948f29c4bd50908491da704536af1106aa87553f6a76cc126c6833dc9b14dd00564b8 *${REVISION}.tar.gz" \ + && if [ "$(openssl sha512 -r ${REVISION}.tar.gz)" = "$PKGOSSCHECKSUM" ]; then \ + echo "pkg-oss tarball checksum verification succeeded!"; \ + else \ + echo "pkg-oss tarball checksum verification failed!"; \ + exit 1; \ + fi \ + && tar xzvf ${REVISION}.tar.gz \ + && cd pkg-oss-${REVISION} \ + && cd debian \ + && for target in base module-geoip module-image-filter module-njs module-xslt; do \ + make rules-$target; \ + mk-build-deps --install --tool="apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends --yes" \ + debuild-$target/nginx-$NGINX_VERSION/debian/control; \ + done \ + && make base module-geoip module-image-filter module-njs module-xslt \ ) \ # we don't remove APT lists here because they get re-downloaded and removed later \ @@ -103,6 +133,7 @@ RUN set -x \ COPY docker-entrypoint.sh / COPY 10-listen-on-ipv6-by-default.sh /docker-entrypoint.d +COPY 15-local-resolvers.envsh /docker-entrypoint.d COPY 20-envsubst-on-templates.sh /docker-entrypoint.d COPY 30-tune-worker-processes.sh /docker-entrypoint.d ENTRYPOINT ["/docker-entrypoint.sh"] diff --git a/mainline/debian/docker-entrypoint.sh b/mainline/debian/docker-entrypoint.sh index 72d5cd94e..8ea04f217 100755 --- a/mainline/debian/docker-entrypoint.sh +++ b/mainline/debian/docker-entrypoint.sh @@ -3,35 +3,44 @@ set -e -if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then - exec 3>&1 -else - exec 3>/dev/null -fi +entrypoint_log() { + if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then + echo "$@" + fi +} -if [ "$1" = "nginx" -o "$1" = "nginx-debug" ]; then +if [ "$1" = "nginx" ] || [ "$1" = "nginx-debug" ]; then if /usr/bin/find "/docker-entrypoint.d/" -mindepth 1 -maxdepth 1 -type f -print -quit 2>/dev/null | read v; then - echo >&3 "$0: /docker-entrypoint.d/ is not empty, will attempt to perform configuration" + entrypoint_log "$0: /docker-entrypoint.d/ is not empty, will attempt to perform configuration" - echo >&3 "$0: Looking for shell scripts in /docker-entrypoint.d/" + entrypoint_log "$0: Looking for shell scripts in /docker-entrypoint.d/" find "/docker-entrypoint.d/" -follow -type f -print | sort -V | while read -r f; do case "$f" in + *.envsh) + if [ -x "$f" ]; then + entrypoint_log "$0: Sourcing $f"; + . "$f" + else + # warn on shell scripts without exec bit + entrypoint_log "$0: Ignoring $f, not executable"; + fi + ;; *.sh) if [ -x "$f" ]; then - echo >&3 "$0: Launching $f"; + entrypoint_log "$0: Launching $f"; "$f" else # warn on shell scripts without exec bit - echo >&3 "$0: Ignoring $f, not executable"; + entrypoint_log "$0: Ignoring $f, not executable"; fi ;; - *) echo >&3 "$0: Ignoring $f";; + *) entrypoint_log "$0: Ignoring $f";; esac done - echo >&3 "$0: Configuration complete; ready for start up" + entrypoint_log "$0: Configuration complete; ready for start up" else - echo >&3 "$0: No files found in /docker-entrypoint.d/, skipping configuration" + entrypoint_log "$0: No files found in /docker-entrypoint.d/, skipping configuration" fi fi diff --git a/modules/Dockerfile b/modules/Dockerfile index 1cce673d2..2e77a0405 100644 --- a/modules/Dockerfile +++ b/modules/Dockerfile @@ -1,23 +1,24 @@ -FROM nginx:mainline as builder +ARG NGINX_FROM_IMAGE=nginx:mainline +FROM ${NGINX_FROM_IMAGE} AS builder ARG ENABLED_MODULES -RUN set -ex \ - && if [ "$ENABLED_MODULES" = "" ]; then \ +SHELL ["/bin/bash", "-exo", "pipefail", "-c"] + +RUN if [ "$ENABLED_MODULES" = "" ]; then \ echo "No additional modules enabled, exiting"; \ exit 1; \ fi COPY ./ /modules/ -RUN set -ex \ - && apt update \ - && apt install -y --no-install-suggests --no-install-recommends \ - patch make wget mercurial devscripts debhelper dpkg-dev \ +RUN apt-get update \ + && apt-get install -y --no-install-suggests --no-install-recommends \ + patch make wget git devscripts debhelper dpkg-dev \ quilt lsb-release build-essential libxml2-utils xsltproc \ equivs git g++ libparse-recdescent-perl \ && XSLSCRIPT_SHA512="f7194c5198daeab9b3b0c3aebf006922c7df1d345d454bd8474489ff2eb6b4bf8e2ffe442489a45d1aab80da6ecebe0097759a1e12cc26b5f0613d05b7c09ffa *stdin" \ - && wget -O /tmp/xslscript.pl https://hg.nginx.org/xslscript/raw-file/01dc9ba12e1b/xslscript.pl \ + && wget -O /tmp/xslscript.pl https://raw.githubusercontent.com/nginx/xslscript/9204424259c343ca08a18a78915f40f28025e093/xslscript.pl \ && if [ "$(cat /tmp/xslscript.pl | openssl sha512 -r)" = "$XSLSCRIPT_SHA512" ]; then \ echo "XSLScript checksum verification succeeded!"; \ chmod +x /tmp/xslscript.pl; \ @@ -26,7 +27,7 @@ RUN set -ex \ echo "XSLScript checksum verification failed!"; \ exit 1; \ fi \ - && hg clone -r ${NGINX_VERSION}-${PKG_RELEASE%%~*} https://hg.nginx.org/pkg-oss/ \ + && git clone -b ${NGINX_VERSION}-${PKG_RELEASE%%~*} https://github.com/nginx/pkg-oss/ \ && cd pkg-oss \ && mkdir /tmp/packages \ && for module in $ENABLED_MODULES; do \ @@ -41,7 +42,7 @@ RUN set -ex \ # some modules require build dependencies if [ -f /modules/$module/build-deps ]; then \ echo "Installing $module build dependencies"; \ - apt update && apt install -y --no-install-suggests --no-install-recommends $(cat /modules/$module/build-deps | xargs); \ + apt-get update && apt-get install -y --no-install-suggests --no-install-recommends $(cat /modules/$module/build-deps | xargs); \ fi; \ # if a module has a build dependency that is not in a distro, provide a # shell script to fetch/build/install those @@ -68,13 +69,11 @@ RUN set -ex \ done \ && echo "BUILT_MODULES=\"$BUILT_MODULES\"" > /tmp/packages/modules.env -FROM nginx:mainline -COPY --from=builder /tmp/packages /tmp/packages -RUN set -ex \ - && apt update \ +FROM ${NGINX_FROM_IMAGE} +RUN --mount=type=bind,target=/tmp/packages/,source=/tmp/packages/,from=builder \ + apt-get update \ && . /tmp/packages/modules.env \ && for module in $BUILT_MODULES; do \ - apt install --no-install-suggests --no-install-recommends -y /tmp/packages/nginx-module-${module}_${NGINX_VERSION}*.deb; \ + apt-get install --no-install-suggests --no-install-recommends -y /tmp/packages/nginx-module-${module}_${NGINX_VERSION}*.deb; \ done \ - && rm -rf /tmp/packages \ && rm -rf /var/lib/apt/lists/ diff --git a/modules/Dockerfile.alpine b/modules/Dockerfile.alpine index d575d5d94..2cdb29366 100644 --- a/modules/Dockerfile.alpine +++ b/modules/Dockerfile.alpine @@ -1,24 +1,25 @@ -FROM nginx:mainline-alpine as builder +ARG NGINX_FROM_IMAGE=nginx:mainline-alpine +FROM ${NGINX_FROM_IMAGE} AS builder ARG ENABLED_MODULES -RUN set -ex \ - && if [ "$ENABLED_MODULES" = "" ]; then \ +SHELL ["/bin/ash", "-exo", "pipefail", "-c"] + +RUN if [ "$ENABLED_MODULES" = "" ]; then \ echo "No additional modules enabled, exiting"; \ exit 1; \ fi COPY ./ /modules/ -RUN set -ex \ - && apk update \ +RUN apk update \ && apk add linux-headers openssl-dev pcre2-dev zlib-dev openssl abuild \ - musl-dev libxslt libxml2-utils make mercurial gcc unzip git \ - xz g++ coreutils \ + musl-dev libxslt libxml2-utils make gcc unzip git \ + xz g++ coreutils curl \ # allow abuild as a root user \ && printf "#!/bin/sh\\nSETFATTR=true /usr/bin/abuild -F \"\$@\"\\n" > /usr/local/bin/abuild \ && chmod +x /usr/local/bin/abuild \ - && hg clone -r ${NGINX_VERSION}-${PKG_RELEASE} https://hg.nginx.org/pkg-oss/ \ + && git clone -b ${NGINX_VERSION}-${PKG_RELEASE} https://github.com/nginx/pkg-oss/ \ && cd pkg-oss \ && mkdir /tmp/packages \ && for module in $ENABLED_MODULES; do \ @@ -60,11 +61,9 @@ RUN set -ex \ done \ && echo "BUILT_MODULES=\"$BUILT_MODULES\"" > /tmp/packages/modules.env -FROM nginx:mainline-alpine -COPY --from=builder /tmp/packages /tmp/packages -RUN set -ex \ - && . /tmp/packages/modules.env \ +FROM ${NGINX_FROM_IMAGE} +RUN --mount=type=bind,target=/tmp/packages/,source=/tmp/packages/,from=builder \ + . /tmp/packages/modules.env \ && for module in $BUILT_MODULES; do \ apk add --no-cache --allow-untrusted /tmp/packages/nginx-module-${module}-${NGINX_VERSION}*.apk; \ - done \ - && rm -rf /tmp/packages + done diff --git a/modules/README.md b/modules/README.md index d5091a0c8..93620e450 100644 --- a/modules/README.md +++ b/modules/README.md @@ -1,9 +1,20 @@ # Adding third-party modules to nginx official image It's possible to extend a mainline image with third-party modules either from -your own instuctions following a simple filesystem layout/syntax using +your own instructions following a simple filesystem layout/syntax using `build_module.sh` helper script, or falling back to package sources from -[pkg-oss](https://hg.nginx.org/pkg-oss). +[pkg-oss](https://github.com/nginx/pkg-oss). + +## Requirements + +To use the Dockerfiles provided here, +[Docker BuildKit](https://docs.docker.com/build/buildkit/) is required. +This is enabled by default as of version 23.0; for earlier versions this can be +enabled by setting the environment variable `DOCKER_BUILDKIT` to `1`. + +If you can not or do not want to use BuildKit, you can use a previous version +of these files, see for example +https://github.com/nginx/docker-nginx/tree/4bf0763f4977fff7e9648add59e0540088f3ca9f/modules. ## Usage @@ -13,7 +24,10 @@ $ docker build --build-arg ENABLED_MODULES="ndk lua" -t my-nginx-with-lua . This command will attempt to build an image called `my-nginx-with-lua` based on official nginx docker hub image with two modules: `ndk` and `lua`. By default, a Debian-based image will be used. If you wish to use Alpine -instead, add `-f Dockerfile.alpine` to the command line. +instead, add `-f Dockerfile.alpine` to the command line. By default, mainline +images are used as a base, but it's possible to specify a different image by +providing `NGINX_FROM_IMAGE` build argument, e.g. `--build-arg +NGINX_FROM_IMAGE=nginx:stable`. The build script will look for module build definition files on filesystem directory under the same name as the module (and resulting package) and if @@ -29,27 +43,24 @@ are available from `pkg-oss` repository: ``` /pkg-oss $ LC_ALL=C make -C debian list-all-modules -make: Entering directory '/pkg-oss/debian' -auth-spnego 1.1.0-1 -brotli 1.0.0-1 -encrypted-session 0.08-1 -fips-check 0.1-1 -geoip 1.21.0-1 -geoip2 3.3-1 -headers-more 0.33-1 -image-filter 1.21.0-1 -lua 0.10.19-1 -modsecurity 1.0.1-2 -ndk 0.3.1-1 -njs 0.5.3-1 -opentracing 0.14.0-1 -passenger 6.0.8-1 -perl 1.21.0-1 -rtmp 1.2.1-1 -set-misc 0.32-1 -subs-filter 0.6.4-1 -xslt 1.21.0-1 -make: Leaving directory '/pkg-oss/debian' +auth-spnego 1.1.2-1 +brotli 1.0.0-1 +encrypted-session 0.09-1 +fips-check 0.1-1 +geoip 1.27.4-1 +geoip2 3.4-1 +headers-more 0.37-1 +image-filter 1.27.4-1 +lua 0.10.28-1 +ndk 0.3.3-1 +njs 0.8.9-1 +otel 0.1.1-1 +passenger 6.0.26-1 +perl 1.27.4-1 +rtmp 1.2.2-1 +set-misc 0.33-1 +subs-filter 0.6.4-1 +xslt 1.27.4-1 ``` If you still want to provide your own instructions for a specific module, @@ -89,7 +100,7 @@ reproduce with a vanilla image first. ### docker-compose with pre-packaged modules If desired modules are already packaged in -[pkg-oss](https://hg.nginx.org/pkg-oss/) - e.g. `debian/Makefile.module-*` +[pkg-oss](https://github.com/nginx/pkg-oss/) - e.g. `debian/Makefile.module-*` exists for a given module, you can use this example. 1. Create a directory for your project: @@ -103,7 +114,7 @@ cd myapp ``` mkdir my-nginx -curl -o my-nginx/Dockerfile https://raw.githubusercontent.com/nginxinc/docker-nginx/master/modules/Dockerfile +curl -o my-nginx/Dockerfile https://raw.githubusercontent.com/nginx/docker-nginx/master/modules/Dockerfile ``` 3. Create a `docker-compose.yml` file: @@ -145,7 +156,7 @@ cd myapp-cache ``` mkdir my-nginx -curl -o my-nginx/Dockerfile https://raw.githubusercontent.com/nginxinc/docker-nginx/master/modules/Dockerfile +curl -o my-nginx/Dockerfile https://raw.githubusercontent.com/nginx/docker-nginx/master/modules/Dockerfile mkdir my-nginx/cachepurge echo "https://github.com/FRiCKLE/ngx_cache_purge/archive/2.3.tar.gz" > my-nginx/cachepurge/source ``` diff --git a/modules/echo/source b/modules/echo/source index 3a6ad274d..78cb376e9 100644 --- a/modules/echo/source +++ b/modules/echo/source @@ -1 +1 @@ -https://github.com/openresty/echo-nginx-module/archive/v0.62.tar.gz +https://github.com/openresty/echo-nginx-module/archive/v0.63.tar.gz diff --git a/stable/alpine-otel/Dockerfile b/stable/alpine-otel/Dockerfile new file mode 100644 index 000000000..7ca1a94b4 --- /dev/null +++ b/stable/alpine-otel/Dockerfile @@ -0,0 +1,77 @@ +# +# NOTE: THIS DOCKERFILE IS GENERATED VIA "update.sh" +# +# PLEASE DO NOT EDIT IT DIRECTLY. +# +FROM nginx:1.28.0-alpine + +ENV OTEL_VERSION 0.1.2 + +RUN set -x \ + && apkArch="$(cat /etc/apk/arch)" \ + && nginxPackages=" \ + nginx=${NGINX_VERSION}-r${PKG_RELEASE} \ + nginx-module-xslt=${NGINX_VERSION}-r${DYNPKG_RELEASE} \ + nginx-module-geoip=${NGINX_VERSION}-r${DYNPKG_RELEASE} \ + nginx-module-image-filter=${NGINX_VERSION}-r${DYNPKG_RELEASE} \ + nginx-module-njs=${NGINX_VERSION}.${NJS_VERSION}-r${NJS_RELEASE} \ + nginx-module-otel=${NGINX_VERSION}.${OTEL_VERSION}-r${PKG_RELEASE} \ + " \ +# install prerequisites for public key and pkg-oss checks + && apk add --no-cache --virtual .checksum-deps \ + openssl \ + && case "$apkArch" in \ + x86_64|aarch64) \ +# arches officially built by upstream + apk add -X "https://nginx.org/packages/alpine/v$(egrep -o '^[0-9]+\.[0-9]+' /etc/alpine-release)/main" --no-cache $nginxPackages \ + ;; \ + *) \ +# we're on an architecture upstream doesn't officially build for +# let's build binaries from the published packaging sources + set -x \ + && tempDir="$(mktemp -d)" \ + && chown nobody:nobody $tempDir \ + && apk add --no-cache --virtual .build-deps \ + gcc \ + libc-dev \ + make \ + openssl-dev \ + pcre2-dev \ + zlib-dev \ + linux-headers \ + cmake \ + bash \ + alpine-sdk \ + findutils \ + curl \ + xz \ + protobuf-dev \ + grpc-dev \ + && su nobody -s /bin/sh -c " \ + export HOME=${tempDir} \ + && cd ${tempDir} \ + && curl -f -L -O https://github.com/nginx/pkg-oss/archive/${NGINX_VERSION}-${PKG_RELEASE}.tar.gz \ + && PKGOSSCHECKSUM=\"517bc18954ccf4efddd51986584ca1f37966833ad342a297e1fe58fd0faf14c5a4dabcb23519dca433878a2927a95d6bea05a6749ee2fa67a33bf24cdc41b1e4 *${NGINX_VERSION}-${PKG_RELEASE}.tar.gz\" \ + && if [ \"\$(openssl sha512 -r ${NGINX_VERSION}-${PKG_RELEASE}.tar.gz)\" = \"\$PKGOSSCHECKSUM\" ]; then \ + echo \"pkg-oss tarball checksum verification succeeded!\"; \ + else \ + echo \"pkg-oss tarball checksum verification failed!\"; \ + exit 1; \ + fi \ + && tar xzvf ${NGINX_VERSION}-${PKG_RELEASE}.tar.gz \ + && cd pkg-oss-${NGINX_VERSION}-${PKG_RELEASE} \ + && cd alpine \ + && make module-otel \ + && apk index --allow-untrusted -o ${tempDir}/packages/alpine/${apkArch}/APKINDEX.tar.gz ${tempDir}/packages/alpine/${apkArch}/*.apk \ + && abuild-sign -k ${tempDir}/.abuild/abuild-key.rsa ${tempDir}/packages/alpine/${apkArch}/APKINDEX.tar.gz \ + " \ + && cp ${tempDir}/.abuild/abuild-key.rsa.pub /etc/apk/keys/ \ + && apk del --no-network .build-deps \ + && apk add -X ${tempDir}/packages/alpine/ --no-cache $nginxPackages \ + ;; \ + esac \ +# remove checksum deps + && apk del --no-network .checksum-deps \ +# if we have leftovers from building, let's purge them (including extra, unnecessary build deps) + && if [ -n "$tempDir" ]; then rm -rf "$tempDir"; fi \ + && if [ -f "/etc/apk/keys/abuild-key.rsa.pub" ]; then rm -f /etc/apk/keys/abuild-key.rsa.pub; fi diff --git a/stable/alpine-perl/10-listen-on-ipv6-by-default.sh b/stable/alpine-perl/10-listen-on-ipv6-by-default.sh deleted file mode 100755 index 9585152ba..000000000 --- a/stable/alpine-perl/10-listen-on-ipv6-by-default.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/bin/sh -# vim:sw=4:ts=4:et - -set -e - -ME=$(basename $0) -DEFAULT_CONF_FILE="etc/nginx/conf.d/default.conf" - -# check if we have ipv6 available -if [ ! -f "/proc/net/if_inet6" ]; then - echo >&3 "$ME: info: ipv6 not available" - exit 0 -fi - -if [ ! -f "/$DEFAULT_CONF_FILE" ]; then - echo >&3 "$ME: info: /$DEFAULT_CONF_FILE is not a file or does not exist" - exit 0 -fi - -# check if the file can be modified, e.g. not on a r/o filesystem -touch /$DEFAULT_CONF_FILE 2>/dev/null || { echo >&3 "$ME: info: can not modify /$DEFAULT_CONF_FILE (read-only file system?)"; exit 0; } - -# check if the file is already modified, e.g. on a container restart -grep -q "listen \[::]\:80;" /$DEFAULT_CONF_FILE && { echo >&3 "$ME: info: IPv6 listen already enabled"; exit 0; } - -if [ -f "/etc/os-release" ]; then - . /etc/os-release -else - echo >&3 "$ME: info: can not guess the operating system" - exit 0 -fi - -echo >&3 "$ME: info: Getting the checksum of /$DEFAULT_CONF_FILE" - -case "$ID" in - "debian") - CHECKSUM=$(dpkg-query --show --showformat='${Conffiles}\n' nginx | grep $DEFAULT_CONF_FILE | cut -d' ' -f 3) - echo "$CHECKSUM /$DEFAULT_CONF_FILE" | md5sum -c - >/dev/null 2>&1 || { - echo >&3 "$ME: info: /$DEFAULT_CONF_FILE differs from the packaged version" - exit 0 - } - ;; - "alpine") - CHECKSUM=$(apk manifest nginx 2>/dev/null| grep $DEFAULT_CONF_FILE | cut -d' ' -f 1 | cut -d ':' -f 2) - echo "$CHECKSUM /$DEFAULT_CONF_FILE" | sha1sum -c - >/dev/null 2>&1 || { - echo >&3 "$ME: info: /$DEFAULT_CONF_FILE differs from the packaged version" - exit 0 - } - ;; - *) - echo >&3 "$ME: info: Unsupported distribution" - exit 0 - ;; -esac - -# enable ipv6 on default.conf listen sockets -sed -i -E 's,listen 80;,listen 80;\n listen [::]:80;,' /$DEFAULT_CONF_FILE - -echo >&3 "$ME: info: Enabled listen on IPv6 in /$DEFAULT_CONF_FILE" - -exit 0 diff --git a/stable/alpine-perl/20-envsubst-on-templates.sh b/stable/alpine-perl/20-envsubst-on-templates.sh deleted file mode 100755 index 4f330295b..000000000 --- a/stable/alpine-perl/20-envsubst-on-templates.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/sh - -set -e - -ME=$(basename $0) - -auto_envsubst() { - local template_dir="${NGINX_ENVSUBST_TEMPLATE_DIR:-/etc/nginx/templates}" - local suffix="${NGINX_ENVSUBST_TEMPLATE_SUFFIX:-.template}" - local output_dir="${NGINX_ENVSUBST_OUTPUT_DIR:-/etc/nginx/conf.d}" - - local template defined_envs relative_path output_path subdir - defined_envs=$(printf '${%s} ' $(env | cut -d= -f1)) - [ -d "$template_dir" ] || return 0 - if [ ! -w "$output_dir" ]; then - echo >&3 "$ME: ERROR: $template_dir exists, but $output_dir is not writable" - return 0 - fi - find "$template_dir" -follow -type f -name "*$suffix" -print | while read -r template; do - relative_path="${template#$template_dir/}" - output_path="$output_dir/${relative_path%$suffix}" - subdir=$(dirname "$relative_path") - # create a subdirectory where the template file exists - mkdir -p "$output_dir/$subdir" - echo >&3 "$ME: Running envsubst on $template to $output_path" - envsubst "$defined_envs" < "$template" > "$output_path" - done -} - -auto_envsubst - -exit 0 diff --git a/stable/alpine-perl/30-tune-worker-processes.sh b/stable/alpine-perl/30-tune-worker-processes.sh deleted file mode 100755 index 565058715..000000000 --- a/stable/alpine-perl/30-tune-worker-processes.sh +++ /dev/null @@ -1,188 +0,0 @@ -#!/bin/sh -# vim:sw=2:ts=2:sts=2:et - -set -eu - -LC_ALL=C -ME=$( basename "$0" ) -PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin - -[ "${NGINX_ENTRYPOINT_WORKER_PROCESSES_AUTOTUNE:-}" ] || exit 0 - -touch /etc/nginx/nginx.conf 2>/dev/null || { echo >&2 "$ME: error: can not modify /etc/nginx/nginx.conf (read-only file system?)"; exit 0; } - -ceildiv() { - num=$1 - div=$2 - echo $(( (num + div - 1) / div )) -} - -get_cpuset() { - cpusetroot=$1 - cpusetfile=$2 - ncpu=0 - [ -f "$cpusetroot/$cpusetfile" ] || return 1 - for token in $( tr ',' ' ' < "$cpusetroot/$cpusetfile" ); do - case "$token" in - *-*) - count=$( seq $(echo "$token" | tr '-' ' ') | wc -l ) - ncpu=$(( ncpu+count )) - ;; - *) - ncpu=$(( ncpu+1 )) - ;; - esac - done - echo "$ncpu" -} - -get_quota() { - cpuroot=$1 - ncpu=0 - [ -f "$cpuroot/cpu.cfs_quota_us" ] || return 1 - [ -f "$cpuroot/cpu.cfs_period_us" ] || return 1 - cfs_quota=$( cat "$cpuroot/cpu.cfs_quota_us" ) - cfs_period=$( cat "$cpuroot/cpu.cfs_period_us" ) - [ "$cfs_quota" = "-1" ] && return 1 - [ "$cfs_period" = "0" ] && return 1 - ncpu=$( ceildiv "$cfs_quota" "$cfs_period" ) - [ "$ncpu" -gt 0 ] || return 1 - echo "$ncpu" -} - -get_quota_v2() { - cpuroot=$1 - ncpu=0 - [ -f "$cpuroot/cpu.max" ] || return 1 - cfs_quota=$( cut -d' ' -f 1 < "$cpuroot/cpu.max" ) - cfs_period=$( cut -d' ' -f 2 < "$cpuroot/cpu.max" ) - [ "$cfs_quota" = "max" ] && return 1 - [ "$cfs_period" = "0" ] && return 1 - ncpu=$( ceildiv "$cfs_quota" "$cfs_period" ) - [ "$ncpu" -gt 0 ] || return 1 - echo "$ncpu" -} - -get_cgroup_v1_path() { - needle=$1 - found= - foundroot= - mountpoint= - - [ -r "/proc/self/mountinfo" ] || return 1 - [ -r "/proc/self/cgroup" ] || return 1 - - while IFS= read -r line; do - case "$needle" in - "cpuset") - case "$line" in - *cpuset*) - found=$( echo "$line" | cut -d ' ' -f 4,5 ) - break - ;; - esac - ;; - "cpu") - case "$line" in - *cpuset*) - ;; - *cpu,cpuacct*|*cpuacct,cpu|*cpuacct*|*cpu*) - found=$( echo "$line" | cut -d ' ' -f 4,5 ) - break - ;; - esac - esac - done << __EOF__ -$( grep -F -- '- cgroup ' /proc/self/mountinfo ) -__EOF__ - - while IFS= read -r line; do - controller=$( echo "$line" | cut -d: -f 2 ) - case "$needle" in - "cpuset") - case "$controller" in - cpuset) - mountpoint=$( echo "$line" | cut -d: -f 3 ) - break - ;; - esac - ;; - "cpu") - case "$controller" in - cpu,cpuacct|cpuacct,cpu|cpuacct|cpu) - mountpoint=$( echo "$line" | cut -d: -f 3 ) - break - ;; - esac - ;; - esac -done << __EOF__ -$( grep -F -- 'cpu' /proc/self/cgroup ) -__EOF__ - - case "${found%% *}" in - "/") - foundroot="${found##* }$mountpoint" - ;; - "$mountpoint") - foundroot="${found##* }" - ;; - esac - echo "$foundroot" -} - -get_cgroup_v2_path() { - found= - foundroot= - mountpoint= - - [ -r "/proc/self/mountinfo" ] || return 1 - [ -r "/proc/self/cgroup" ] || return 1 - - while IFS= read -r line; do - found=$( echo "$line" | cut -d ' ' -f 4,5 ) - done << __EOF__ -$( grep -F -- '- cgroup2 ' /proc/self/mountinfo ) -__EOF__ - - while IFS= read -r line; do - mountpoint=$( echo "$line" | cut -d: -f 3 ) -done << __EOF__ -$( grep -F -- '0::' /proc/self/cgroup ) -__EOF__ - - case "${found%% *}" in - "") - return 1 - ;; - "/") - foundroot="${found##* }$mountpoint" - ;; - "$mountpoint") - foundroot="${found##* }" - ;; - esac - echo "$foundroot" -} - -ncpu_online=$( getconf _NPROCESSORS_ONLN ) -ncpu_cpuset= -ncpu_quota= -ncpu_cpuset_v2= -ncpu_quota_v2= - -cpuset=$( get_cgroup_v1_path "cpuset" ) && ncpu_cpuset=$( get_cpuset "$cpuset" "cpuset.effective_cpus" ) || ncpu_cpuset=$ncpu_online -cpu=$( get_cgroup_v1_path "cpu" ) && ncpu_quota=$( get_quota "$cpu" ) || ncpu_quota=$ncpu_online -cgroup_v2=$( get_cgroup_v2_path ) && ncpu_cpuset_v2=$( get_cpuset "$cgroup_v2" "cpuset.cpus.effective" ) || ncpu_cpuset_v2=$ncpu_online -cgroup_v2=$( get_cgroup_v2_path ) && ncpu_quota_v2=$( get_quota_v2 "$cgroup_v2" ) || ncpu_quota_v2=$ncpu_online - -ncpu=$( printf "%s\n%s\n%s\n%s\n%s\n" \ - "$ncpu_online" \ - "$ncpu_cpuset" \ - "$ncpu_quota" \ - "$ncpu_cpuset_v2" \ - "$ncpu_quota_v2" \ - | sort -n \ - | head -n 1 ) - -sed -i.bak -r 's/^(worker_processes)(.*)$/# Commented out by '"$ME"' on '"$(date)"'\n#\1\2\n\1 '"$ncpu"';/' /etc/nginx/nginx.conf diff --git a/stable/alpine-perl/Dockerfile b/stable/alpine-perl/Dockerfile index 4f89d0292..9676d8bc5 100644 --- a/stable/alpine-perl/Dockerfile +++ b/stable/alpine-perl/Dockerfile @@ -3,26 +3,17 @@ # # PLEASE DO NOT EDIT IT DIRECTLY. # -FROM alpine:3.16 - -LABEL maintainer="NGINX Docker Maintainers " - -ENV NGINX_VERSION 1.22.0 -ENV NJS_VERSION 0.7.5 -ENV PKG_RELEASE 1 +FROM nginx:1.28.0-alpine RUN set -x \ -# create nginx user/group first, to be consistent throughout docker variants - && addgroup -g 101 -S nginx \ - && adduser -S -D -H -u 101 -h /var/cache/nginx -s /sbin/nologin -G nginx -g nginx nginx \ && apkArch="$(cat /etc/apk/arch)" \ && nginxPackages=" \ nginx=${NGINX_VERSION}-r${PKG_RELEASE} \ - nginx-module-xslt=${NGINX_VERSION}-r${PKG_RELEASE} \ - nginx-module-geoip=${NGINX_VERSION}-r${PKG_RELEASE} \ - nginx-module-image-filter=${NGINX_VERSION}-r${PKG_RELEASE} \ - nginx-module-perl=${NGINX_VERSION}-r${PKG_RELEASE} \ - nginx-module-njs=${NGINX_VERSION}.${NJS_VERSION}-r${PKG_RELEASE} \ + nginx-module-xslt=${NGINX_VERSION}-r${DYNPKG_RELEASE} \ + nginx-module-geoip=${NGINX_VERSION}-r${DYNPKG_RELEASE} \ + nginx-module-image-filter=${NGINX_VERSION}-r${DYNPKG_RELEASE} \ + nginx-module-perl=${NGINX_VERSION}-r${DYNPKG_RELEASE} \ + nginx-module-njs=${NGINX_VERSION}.${NJS_VERSION}-r${NJS_RELEASE} \ " \ # install prerequisites for public key and pkg-oss checks && apk add --no-cache --virtual .checksum-deps \ @@ -30,17 +21,7 @@ RUN set -x \ && case "$apkArch" in \ x86_64|aarch64) \ # arches officially built by upstream - set -x \ - && KEY_SHA512="e7fa8303923d9b95db37a77ad46c68fd4755ff935d0a534d26eba83de193c76166c68bfe7f65471bf8881004ef4aa6df3e34689c305662750c0172fca5d8552a *stdin" \ - && wget -O /tmp/nginx_signing.rsa.pub https://nginx.org/keys/nginx_signing.rsa.pub \ - && if [ "$(openssl rsa -pubin -in /tmp/nginx_signing.rsa.pub -text -noout | openssl sha512 -r)" = "$KEY_SHA512" ]; then \ - echo "key verification succeeded!"; \ - mv /tmp/nginx_signing.rsa.pub /etc/apk/keys/; \ - else \ - echo "key verification failed!"; \ - exit 1; \ - fi \ - && apk add -X "https://nginx.org/packages/alpine/v$(egrep -o '^[0-9]+\.[0-9]+' /etc/alpine-release)/main" --no-cache $nginxPackages \ + apk add -X "https://nginx.org/packages/alpine/v$(egrep -o '^[0-9]+\.[0-9]+' /etc/alpine-release)/main" --no-cache $nginxPackages \ ;; \ *) \ # we're on an architecture upstream doesn't officially build for @@ -56,79 +37,36 @@ RUN set -x \ pcre2-dev \ zlib-dev \ linux-headers \ - libxslt-dev \ - gd-dev \ - geoip-dev \ perl-dev \ - libedit-dev \ bash \ alpine-sdk \ findutils \ + curl \ && su nobody -s /bin/sh -c " \ export HOME=${tempDir} \ && cd ${tempDir} \ - && curl -f -O https://hg.nginx.org/pkg-oss/archive/714.tar.gz \ - && PKGOSSCHECKSUM=\"f457d5988c1f2663e04c5cdad71874c25e94754277dd9da5d73c1d37c32bdaf288b3b20d8b5d070ffb33aab363eaf4a7abbcf95fcfd72b0729a1c1908c37e30e *714.tar.gz\" \ - && if [ \"\$(openssl sha512 -r 714.tar.gz)\" = \"\$PKGOSSCHECKSUM\" ]; then \ + && curl -f -L -O https://github.com/nginx/pkg-oss/archive/${NGINX_VERSION}-${PKG_RELEASE}.tar.gz \ + && PKGOSSCHECKSUM=\"517bc18954ccf4efddd51986584ca1f37966833ad342a297e1fe58fd0faf14c5a4dabcb23519dca433878a2927a95d6bea05a6749ee2fa67a33bf24cdc41b1e4 *${NGINX_VERSION}-${PKG_RELEASE}.tar.gz\" \ + && if [ \"\$(openssl sha512 -r ${NGINX_VERSION}-${PKG_RELEASE}.tar.gz)\" = \"\$PKGOSSCHECKSUM\" ]; then \ echo \"pkg-oss tarball checksum verification succeeded!\"; \ else \ echo \"pkg-oss tarball checksum verification failed!\"; \ exit 1; \ fi \ - && tar xzvf 714.tar.gz \ - && cd pkg-oss-714 \ + && tar xzvf ${NGINX_VERSION}-${PKG_RELEASE}.tar.gz \ + && cd pkg-oss-${NGINX_VERSION}-${PKG_RELEASE} \ && cd alpine \ - && make all \ - && apk index -o ${tempDir}/packages/alpine/${apkArch}/APKINDEX.tar.gz ${tempDir}/packages/alpine/${apkArch}/*.apk \ + && make module-perl \ + && apk index --allow-untrusted -o ${tempDir}/packages/alpine/${apkArch}/APKINDEX.tar.gz ${tempDir}/packages/alpine/${apkArch}/*.apk \ && abuild-sign -k ${tempDir}/.abuild/abuild-key.rsa ${tempDir}/packages/alpine/${apkArch}/APKINDEX.tar.gz \ " \ && cp ${tempDir}/.abuild/abuild-key.rsa.pub /etc/apk/keys/ \ - && apk del .build-deps \ + && apk del --no-network .build-deps \ && apk add -X ${tempDir}/packages/alpine/ --no-cache $nginxPackages \ ;; \ esac \ # remove checksum deps - && apk del .checksum-deps \ + && apk del --no-network .checksum-deps \ # if we have leftovers from building, let's purge them (including extra, unnecessary build deps) && if [ -n "$tempDir" ]; then rm -rf "$tempDir"; fi \ - && if [ -n "/etc/apk/keys/abuild-key.rsa.pub" ]; then rm -f /etc/apk/keys/abuild-key.rsa.pub; fi \ - && if [ -n "/etc/apk/keys/nginx_signing.rsa.pub" ]; then rm -f /etc/apk/keys/nginx_signing.rsa.pub; fi \ -# Bring in gettext so we can get `envsubst`, then throw -# the rest away. To do this, we need to install `gettext` -# then move `envsubst` out of the way so `gettext` can -# be deleted completely, then move `envsubst` back. - && apk add --no-cache --virtual .gettext gettext \ - && mv /usr/bin/envsubst /tmp/ \ - \ - && runDeps="$( \ - scanelf --needed --nobanner /tmp/envsubst \ - | awk '{ gsub(/,/, "\nso:", $2); print "so:" $2 }' \ - | sort -u \ - | xargs -r apk info --installed \ - | sort -u \ - )" \ - && apk add --no-cache $runDeps \ - && apk del .gettext \ - && mv /tmp/envsubst /usr/local/bin/ \ -# Bring in tzdata so users could set the timezones through the environment -# variables - && apk add --no-cache tzdata \ -# Bring in curl and ca-certificates to make registering on DNS SD easier - && apk add --no-cache curl ca-certificates \ -# forward request and error logs to docker log collector - && ln -sf /dev/stdout /var/log/nginx/access.log \ - && ln -sf /dev/stderr /var/log/nginx/error.log \ -# create a docker-entrypoint.d directory - && mkdir /docker-entrypoint.d - -COPY docker-entrypoint.sh / -COPY 10-listen-on-ipv6-by-default.sh /docker-entrypoint.d -COPY 20-envsubst-on-templates.sh /docker-entrypoint.d -COPY 30-tune-worker-processes.sh /docker-entrypoint.d -ENTRYPOINT ["/docker-entrypoint.sh"] - -EXPOSE 80 - -STOPSIGNAL SIGQUIT - -CMD ["nginx", "-g", "daemon off;"] + && if [ -f "/etc/apk/keys/abuild-key.rsa.pub" ]; then rm -f /etc/apk/keys/abuild-key.rsa.pub; fi diff --git a/stable/alpine-perl/docker-entrypoint.sh b/stable/alpine-perl/docker-entrypoint.sh deleted file mode 100755 index 72d5cd94e..000000000 --- a/stable/alpine-perl/docker-entrypoint.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh -# vim:sw=4:ts=4:et - -set -e - -if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then - exec 3>&1 -else - exec 3>/dev/null -fi - -if [ "$1" = "nginx" -o "$1" = "nginx-debug" ]; then - if /usr/bin/find "/docker-entrypoint.d/" -mindepth 1 -maxdepth 1 -type f -print -quit 2>/dev/null | read v; then - echo >&3 "$0: /docker-entrypoint.d/ is not empty, will attempt to perform configuration" - - echo >&3 "$0: Looking for shell scripts in /docker-entrypoint.d/" - find "/docker-entrypoint.d/" -follow -type f -print | sort -V | while read -r f; do - case "$f" in - *.sh) - if [ -x "$f" ]; then - echo >&3 "$0: Launching $f"; - "$f" - else - # warn on shell scripts without exec bit - echo >&3 "$0: Ignoring $f, not executable"; - fi - ;; - *) echo >&3 "$0: Ignoring $f";; - esac - done - - echo >&3 "$0: Configuration complete; ready for start up" - else - echo >&3 "$0: No files found in /docker-entrypoint.d/, skipping configuration" - fi -fi - -exec "$@" diff --git a/mainline/alpine/10-listen-on-ipv6-by-default.sh b/stable/alpine-slim/10-listen-on-ipv6-by-default.sh similarity index 53% rename from mainline/alpine/10-listen-on-ipv6-by-default.sh rename to stable/alpine-slim/10-listen-on-ipv6-by-default.sh index 9585152ba..61a901dee 100755 --- a/mainline/alpine/10-listen-on-ipv6-by-default.sh +++ b/stable/alpine-slim/10-listen-on-ipv6-by-default.sh @@ -3,52 +3,58 @@ set -e -ME=$(basename $0) +entrypoint_log() { + if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then + echo "$@" + fi +} + +ME=$(basename "$0") DEFAULT_CONF_FILE="etc/nginx/conf.d/default.conf" # check if we have ipv6 available if [ ! -f "/proc/net/if_inet6" ]; then - echo >&3 "$ME: info: ipv6 not available" + entrypoint_log "$ME: info: ipv6 not available" exit 0 fi if [ ! -f "/$DEFAULT_CONF_FILE" ]; then - echo >&3 "$ME: info: /$DEFAULT_CONF_FILE is not a file or does not exist" + entrypoint_log "$ME: info: /$DEFAULT_CONF_FILE is not a file or does not exist" exit 0 fi # check if the file can be modified, e.g. not on a r/o filesystem -touch /$DEFAULT_CONF_FILE 2>/dev/null || { echo >&3 "$ME: info: can not modify /$DEFAULT_CONF_FILE (read-only file system?)"; exit 0; } +touch /$DEFAULT_CONF_FILE 2>/dev/null || { entrypoint_log "$ME: info: can not modify /$DEFAULT_CONF_FILE (read-only file system?)"; exit 0; } # check if the file is already modified, e.g. on a container restart -grep -q "listen \[::]\:80;" /$DEFAULT_CONF_FILE && { echo >&3 "$ME: info: IPv6 listen already enabled"; exit 0; } +grep -q "listen \[::\]:80;" /$DEFAULT_CONF_FILE && { entrypoint_log "$ME: info: IPv6 listen already enabled"; exit 0; } if [ -f "/etc/os-release" ]; then . /etc/os-release else - echo >&3 "$ME: info: can not guess the operating system" + entrypoint_log "$ME: info: can not guess the operating system" exit 0 fi -echo >&3 "$ME: info: Getting the checksum of /$DEFAULT_CONF_FILE" +entrypoint_log "$ME: info: Getting the checksum of /$DEFAULT_CONF_FILE" case "$ID" in "debian") CHECKSUM=$(dpkg-query --show --showformat='${Conffiles}\n' nginx | grep $DEFAULT_CONF_FILE | cut -d' ' -f 3) echo "$CHECKSUM /$DEFAULT_CONF_FILE" | md5sum -c - >/dev/null 2>&1 || { - echo >&3 "$ME: info: /$DEFAULT_CONF_FILE differs from the packaged version" + entrypoint_log "$ME: info: /$DEFAULT_CONF_FILE differs from the packaged version" exit 0 } ;; "alpine") CHECKSUM=$(apk manifest nginx 2>/dev/null| grep $DEFAULT_CONF_FILE | cut -d' ' -f 1 | cut -d ':' -f 2) echo "$CHECKSUM /$DEFAULT_CONF_FILE" | sha1sum -c - >/dev/null 2>&1 || { - echo >&3 "$ME: info: /$DEFAULT_CONF_FILE differs from the packaged version" + entrypoint_log "$ME: info: /$DEFAULT_CONF_FILE differs from the packaged version" exit 0 } ;; *) - echo >&3 "$ME: info: Unsupported distribution" + entrypoint_log "$ME: info: Unsupported distribution" exit 0 ;; esac @@ -56,6 +62,6 @@ esac # enable ipv6 on default.conf listen sockets sed -i -E 's,listen 80;,listen 80;\n listen [::]:80;,' /$DEFAULT_CONF_FILE -echo >&3 "$ME: info: Enabled listen on IPv6 in /$DEFAULT_CONF_FILE" +entrypoint_log "$ME: info: Enabled listen on IPv6 in /$DEFAULT_CONF_FILE" exit 0 diff --git a/stable/alpine-slim/15-local-resolvers.envsh b/stable/alpine-slim/15-local-resolvers.envsh new file mode 100755 index 000000000..e830ddacd --- /dev/null +++ b/stable/alpine-slim/15-local-resolvers.envsh @@ -0,0 +1,15 @@ +#!/bin/sh +# vim:sw=2:ts=2:sts=2:et + +set -eu + +LC_ALL=C +PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin + +[ "${NGINX_ENTRYPOINT_LOCAL_RESOLVERS:-}" ] || return 0 + +NGINX_LOCAL_RESOLVERS=$(awk 'BEGIN{ORS=" "} $1=="nameserver" {if ($2 ~ ":") {print "["$2"]"} else {print $2}}' /etc/resolv.conf) + +NGINX_LOCAL_RESOLVERS="${NGINX_LOCAL_RESOLVERS% }" + +export NGINX_LOCAL_RESOLVERS diff --git a/stable/alpine-slim/20-envsubst-on-templates.sh b/stable/alpine-slim/20-envsubst-on-templates.sh new file mode 100755 index 000000000..3804165c9 --- /dev/null +++ b/stable/alpine-slim/20-envsubst-on-templates.sh @@ -0,0 +1,78 @@ +#!/bin/sh + +set -e + +ME=$(basename "$0") + +entrypoint_log() { + if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then + echo "$@" + fi +} + +add_stream_block() { + local conffile="/etc/nginx/nginx.conf" + + if grep -q -E "\s*stream\s*\{" "$conffile"; then + entrypoint_log "$ME: $conffile contains a stream block; include $stream_output_dir/*.conf to enable stream templates" + else + # check if the file can be modified, e.g. not on a r/o filesystem + touch "$conffile" 2>/dev/null || { entrypoint_log "$ME: info: can not modify $conffile (read-only file system?)"; exit 0; } + entrypoint_log "$ME: Appending stream block to $conffile to include $stream_output_dir/*.conf" + cat << END >> "$conffile" +# added by "$ME" on "$(date)" +stream { + include $stream_output_dir/*.conf; +} +END + fi +} + +auto_envsubst() { + local template_dir="${NGINX_ENVSUBST_TEMPLATE_DIR:-/etc/nginx/templates}" + local suffix="${NGINX_ENVSUBST_TEMPLATE_SUFFIX:-.template}" + local output_dir="${NGINX_ENVSUBST_OUTPUT_DIR:-/etc/nginx/conf.d}" + local stream_suffix="${NGINX_ENVSUBST_STREAM_TEMPLATE_SUFFIX:-.stream-template}" + local stream_output_dir="${NGINX_ENVSUBST_STREAM_OUTPUT_DIR:-/etc/nginx/stream-conf.d}" + local filter="${NGINX_ENVSUBST_FILTER:-}" + + local template defined_envs relative_path output_path subdir + defined_envs=$(printf '${%s} ' $(awk "END { for (name in ENVIRON) { print ( name ~ /${filter}/ ) ? name : \"\" } }" < /dev/null )) + [ -d "$template_dir" ] || return 0 + if [ ! -w "$output_dir" ]; then + entrypoint_log "$ME: ERROR: $template_dir exists, but $output_dir is not writable" + return 0 + fi + find "$template_dir" -follow -type f -name "*$suffix" -print | while read -r template; do + relative_path="${template#"$template_dir/"}" + output_path="$output_dir/${relative_path%"$suffix"}" + subdir=$(dirname "$relative_path") + # create a subdirectory where the template file exists + mkdir -p "$output_dir/$subdir" + entrypoint_log "$ME: Running envsubst on $template to $output_path" + envsubst "$defined_envs" < "$template" > "$output_path" + done + + # Print the first file with the stream suffix, this will be false if there are none + if test -n "$(find "$template_dir" -name "*$stream_suffix" -print -quit)"; then + mkdir -p "$stream_output_dir" + if [ ! -w "$stream_output_dir" ]; then + entrypoint_log "$ME: ERROR: $template_dir exists, but $stream_output_dir is not writable" + return 0 + fi + add_stream_block + find "$template_dir" -follow -type f -name "*$stream_suffix" -print | while read -r template; do + relative_path="${template#"$template_dir/"}" + output_path="$stream_output_dir/${relative_path%"$stream_suffix"}" + subdir=$(dirname "$relative_path") + # create a subdirectory where the template file exists + mkdir -p "$stream_output_dir/$subdir" + entrypoint_log "$ME: Running envsubst on $template to $output_path" + envsubst "$defined_envs" < "$template" > "$output_path" + done + fi +} + +auto_envsubst + +exit 0 diff --git a/mainline/debian-perl/30-tune-worker-processes.sh b/stable/alpine-slim/30-tune-worker-processes.sh similarity index 98% rename from mainline/debian-perl/30-tune-worker-processes.sh rename to stable/alpine-slim/30-tune-worker-processes.sh index 565058715..defb994f3 100755 --- a/mainline/debian-perl/30-tune-worker-processes.sh +++ b/stable/alpine-slim/30-tune-worker-processes.sh @@ -4,7 +4,7 @@ set -eu LC_ALL=C -ME=$( basename "$0" ) +ME=$(basename "$0") PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin [ "${NGINX_ENTRYPOINT_WORKER_PROCESSES_AUTOTUNE:-}" ] || exit 0 @@ -158,7 +158,7 @@ __EOF__ "/") foundroot="${found##* }$mountpoint" ;; - "$mountpoint") + "$mountpoint" | /../*) foundroot="${found##* }" ;; esac diff --git a/stable/alpine-slim/Dockerfile b/stable/alpine-slim/Dockerfile new file mode 100644 index 000000000..29bf5ba2a --- /dev/null +++ b/stable/alpine-slim/Dockerfile @@ -0,0 +1,108 @@ +# +# NOTE: THIS DOCKERFILE IS GENERATED VIA "update.sh" +# +# PLEASE DO NOT EDIT IT DIRECTLY. +# +FROM alpine:3.21 + +LABEL maintainer="NGINX Docker Maintainers " + +ENV NGINX_VERSION 1.28.0 +ENV PKG_RELEASE 1 +ENV DYNPKG_RELEASE 1 + +RUN set -x \ +# create nginx user/group first, to be consistent throughout docker variants + && addgroup -g 101 -S nginx \ + && adduser -S -D -H -u 101 -h /var/cache/nginx -s /sbin/nologin -G nginx -g nginx nginx \ + && apkArch="$(cat /etc/apk/arch)" \ + && nginxPackages=" \ + nginx=${NGINX_VERSION}-r${PKG_RELEASE} \ + " \ +# install prerequisites for public key and pkg-oss checks + && apk add --no-cache --virtual .checksum-deps \ + openssl \ + && case "$apkArch" in \ + x86_64|aarch64) \ +# arches officially built by upstream + set -x \ + && KEY_SHA512="e09fa32f0a0eab2b879ccbbc4d0e4fb9751486eedda75e35fac65802cc9faa266425edf83e261137a2f4d16281ce2c1a5f4502930fe75154723da014214f0655" \ + && wget -O /tmp/nginx_signing.rsa.pub https://nginx.org/keys/nginx_signing.rsa.pub \ + && if echo "$KEY_SHA512 */tmp/nginx_signing.rsa.pub" | sha512sum -c -; then \ + echo "key verification succeeded!"; \ + mv /tmp/nginx_signing.rsa.pub /etc/apk/keys/; \ + else \ + echo "key verification failed!"; \ + exit 1; \ + fi \ + && apk add -X "https://nginx.org/packages/alpine/v$(egrep -o '^[0-9]+\.[0-9]+' /etc/alpine-release)/main" --no-cache $nginxPackages \ + ;; \ + *) \ +# we're on an architecture upstream doesn't officially build for +# let's build binaries from the published packaging sources + set -x \ + && tempDir="$(mktemp -d)" \ + && chown nobody:nobody $tempDir \ + && apk add --no-cache --virtual .build-deps \ + gcc \ + libc-dev \ + make \ + openssl-dev \ + pcre2-dev \ + zlib-dev \ + linux-headers \ + bash \ + alpine-sdk \ + findutils \ + curl \ + && su nobody -s /bin/sh -c " \ + export HOME=${tempDir} \ + && cd ${tempDir} \ + && curl -f -L -O https://github.com/nginx/pkg-oss/archive/${NGINX_VERSION}-${PKG_RELEASE}.tar.gz \ + && PKGOSSCHECKSUM=\"517bc18954ccf4efddd51986584ca1f37966833ad342a297e1fe58fd0faf14c5a4dabcb23519dca433878a2927a95d6bea05a6749ee2fa67a33bf24cdc41b1e4 *${NGINX_VERSION}-${PKG_RELEASE}.tar.gz\" \ + && if [ \"\$(openssl sha512 -r ${NGINX_VERSION}-${PKG_RELEASE}.tar.gz)\" = \"\$PKGOSSCHECKSUM\" ]; then \ + echo \"pkg-oss tarball checksum verification succeeded!\"; \ + else \ + echo \"pkg-oss tarball checksum verification failed!\"; \ + exit 1; \ + fi \ + && tar xzvf ${NGINX_VERSION}-${PKG_RELEASE}.tar.gz \ + && cd pkg-oss-${NGINX_VERSION}-${PKG_RELEASE} \ + && cd alpine \ + && make base \ + && apk index --allow-untrusted -o ${tempDir}/packages/alpine/${apkArch}/APKINDEX.tar.gz ${tempDir}/packages/alpine/${apkArch}/*.apk \ + && abuild-sign -k ${tempDir}/.abuild/abuild-key.rsa ${tempDir}/packages/alpine/${apkArch}/APKINDEX.tar.gz \ + " \ + && cp ${tempDir}/.abuild/abuild-key.rsa.pub /etc/apk/keys/ \ + && apk del --no-network .build-deps \ + && apk add -X ${tempDir}/packages/alpine/ --no-cache $nginxPackages \ + ;; \ + esac \ +# remove checksum deps + && apk del --no-network .checksum-deps \ +# if we have leftovers from building, let's purge them (including extra, unnecessary build deps) + && if [ -n "$tempDir" ]; then rm -rf "$tempDir"; fi \ + && if [ -f "/etc/apk/keys/abuild-key.rsa.pub" ]; then rm -f /etc/apk/keys/abuild-key.rsa.pub; fi \ +# Add `envsubst` for templating environment variables + && apk add --no-cache gettext-envsubst \ +# Bring in tzdata so users could set the timezones through the environment +# variables + && apk add --no-cache tzdata \ +# forward request and error logs to docker log collector + && ln -sf /dev/stdout /var/log/nginx/access.log \ + && ln -sf /dev/stderr /var/log/nginx/error.log \ +# create a docker-entrypoint.d directory + && mkdir /docker-entrypoint.d + +COPY docker-entrypoint.sh / +COPY 10-listen-on-ipv6-by-default.sh /docker-entrypoint.d +COPY 15-local-resolvers.envsh /docker-entrypoint.d +COPY 20-envsubst-on-templates.sh /docker-entrypoint.d +COPY 30-tune-worker-processes.sh /docker-entrypoint.d +ENTRYPOINT ["/docker-entrypoint.sh"] + +EXPOSE 80 + +STOPSIGNAL SIGQUIT + +CMD ["nginx", "-g", "daemon off;"] diff --git a/stable/alpine-slim/docker-entrypoint.sh b/stable/alpine-slim/docker-entrypoint.sh new file mode 100755 index 000000000..8ea04f217 --- /dev/null +++ b/stable/alpine-slim/docker-entrypoint.sh @@ -0,0 +1,47 @@ +#!/bin/sh +# vim:sw=4:ts=4:et + +set -e + +entrypoint_log() { + if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then + echo "$@" + fi +} + +if [ "$1" = "nginx" ] || [ "$1" = "nginx-debug" ]; then + if /usr/bin/find "/docker-entrypoint.d/" -mindepth 1 -maxdepth 1 -type f -print -quit 2>/dev/null | read v; then + entrypoint_log "$0: /docker-entrypoint.d/ is not empty, will attempt to perform configuration" + + entrypoint_log "$0: Looking for shell scripts in /docker-entrypoint.d/" + find "/docker-entrypoint.d/" -follow -type f -print | sort -V | while read -r f; do + case "$f" in + *.envsh) + if [ -x "$f" ]; then + entrypoint_log "$0: Sourcing $f"; + . "$f" + else + # warn on shell scripts without exec bit + entrypoint_log "$0: Ignoring $f, not executable"; + fi + ;; + *.sh) + if [ -x "$f" ]; then + entrypoint_log "$0: Launching $f"; + "$f" + else + # warn on shell scripts without exec bit + entrypoint_log "$0: Ignoring $f, not executable"; + fi + ;; + *) entrypoint_log "$0: Ignoring $f";; + esac + done + + entrypoint_log "$0: Configuration complete; ready for start up" + else + entrypoint_log "$0: No files found in /docker-entrypoint.d/, skipping configuration" + fi +fi + +exec "$@" diff --git a/stable/alpine/10-listen-on-ipv6-by-default.sh b/stable/alpine/10-listen-on-ipv6-by-default.sh deleted file mode 100755 index 9585152ba..000000000 --- a/stable/alpine/10-listen-on-ipv6-by-default.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/bin/sh -# vim:sw=4:ts=4:et - -set -e - -ME=$(basename $0) -DEFAULT_CONF_FILE="etc/nginx/conf.d/default.conf" - -# check if we have ipv6 available -if [ ! -f "/proc/net/if_inet6" ]; then - echo >&3 "$ME: info: ipv6 not available" - exit 0 -fi - -if [ ! -f "/$DEFAULT_CONF_FILE" ]; then - echo >&3 "$ME: info: /$DEFAULT_CONF_FILE is not a file or does not exist" - exit 0 -fi - -# check if the file can be modified, e.g. not on a r/o filesystem -touch /$DEFAULT_CONF_FILE 2>/dev/null || { echo >&3 "$ME: info: can not modify /$DEFAULT_CONF_FILE (read-only file system?)"; exit 0; } - -# check if the file is already modified, e.g. on a container restart -grep -q "listen \[::]\:80;" /$DEFAULT_CONF_FILE && { echo >&3 "$ME: info: IPv6 listen already enabled"; exit 0; } - -if [ -f "/etc/os-release" ]; then - . /etc/os-release -else - echo >&3 "$ME: info: can not guess the operating system" - exit 0 -fi - -echo >&3 "$ME: info: Getting the checksum of /$DEFAULT_CONF_FILE" - -case "$ID" in - "debian") - CHECKSUM=$(dpkg-query --show --showformat='${Conffiles}\n' nginx | grep $DEFAULT_CONF_FILE | cut -d' ' -f 3) - echo "$CHECKSUM /$DEFAULT_CONF_FILE" | md5sum -c - >/dev/null 2>&1 || { - echo >&3 "$ME: info: /$DEFAULT_CONF_FILE differs from the packaged version" - exit 0 - } - ;; - "alpine") - CHECKSUM=$(apk manifest nginx 2>/dev/null| grep $DEFAULT_CONF_FILE | cut -d' ' -f 1 | cut -d ':' -f 2) - echo "$CHECKSUM /$DEFAULT_CONF_FILE" | sha1sum -c - >/dev/null 2>&1 || { - echo >&3 "$ME: info: /$DEFAULT_CONF_FILE differs from the packaged version" - exit 0 - } - ;; - *) - echo >&3 "$ME: info: Unsupported distribution" - exit 0 - ;; -esac - -# enable ipv6 on default.conf listen sockets -sed -i -E 's,listen 80;,listen 80;\n listen [::]:80;,' /$DEFAULT_CONF_FILE - -echo >&3 "$ME: info: Enabled listen on IPv6 in /$DEFAULT_CONF_FILE" - -exit 0 diff --git a/stable/alpine/20-envsubst-on-templates.sh b/stable/alpine/20-envsubst-on-templates.sh deleted file mode 100755 index 4f330295b..000000000 --- a/stable/alpine/20-envsubst-on-templates.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/sh - -set -e - -ME=$(basename $0) - -auto_envsubst() { - local template_dir="${NGINX_ENVSUBST_TEMPLATE_DIR:-/etc/nginx/templates}" - local suffix="${NGINX_ENVSUBST_TEMPLATE_SUFFIX:-.template}" - local output_dir="${NGINX_ENVSUBST_OUTPUT_DIR:-/etc/nginx/conf.d}" - - local template defined_envs relative_path output_path subdir - defined_envs=$(printf '${%s} ' $(env | cut -d= -f1)) - [ -d "$template_dir" ] || return 0 - if [ ! -w "$output_dir" ]; then - echo >&3 "$ME: ERROR: $template_dir exists, but $output_dir is not writable" - return 0 - fi - find "$template_dir" -follow -type f -name "*$suffix" -print | while read -r template; do - relative_path="${template#$template_dir/}" - output_path="$output_dir/${relative_path%$suffix}" - subdir=$(dirname "$relative_path") - # create a subdirectory where the template file exists - mkdir -p "$output_dir/$subdir" - echo >&3 "$ME: Running envsubst on $template to $output_path" - envsubst "$defined_envs" < "$template" > "$output_path" - done -} - -auto_envsubst - -exit 0 diff --git a/stable/alpine/30-tune-worker-processes.sh b/stable/alpine/30-tune-worker-processes.sh deleted file mode 100755 index 565058715..000000000 --- a/stable/alpine/30-tune-worker-processes.sh +++ /dev/null @@ -1,188 +0,0 @@ -#!/bin/sh -# vim:sw=2:ts=2:sts=2:et - -set -eu - -LC_ALL=C -ME=$( basename "$0" ) -PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin - -[ "${NGINX_ENTRYPOINT_WORKER_PROCESSES_AUTOTUNE:-}" ] || exit 0 - -touch /etc/nginx/nginx.conf 2>/dev/null || { echo >&2 "$ME: error: can not modify /etc/nginx/nginx.conf (read-only file system?)"; exit 0; } - -ceildiv() { - num=$1 - div=$2 - echo $(( (num + div - 1) / div )) -} - -get_cpuset() { - cpusetroot=$1 - cpusetfile=$2 - ncpu=0 - [ -f "$cpusetroot/$cpusetfile" ] || return 1 - for token in $( tr ',' ' ' < "$cpusetroot/$cpusetfile" ); do - case "$token" in - *-*) - count=$( seq $(echo "$token" | tr '-' ' ') | wc -l ) - ncpu=$(( ncpu+count )) - ;; - *) - ncpu=$(( ncpu+1 )) - ;; - esac - done - echo "$ncpu" -} - -get_quota() { - cpuroot=$1 - ncpu=0 - [ -f "$cpuroot/cpu.cfs_quota_us" ] || return 1 - [ -f "$cpuroot/cpu.cfs_period_us" ] || return 1 - cfs_quota=$( cat "$cpuroot/cpu.cfs_quota_us" ) - cfs_period=$( cat "$cpuroot/cpu.cfs_period_us" ) - [ "$cfs_quota" = "-1" ] && return 1 - [ "$cfs_period" = "0" ] && return 1 - ncpu=$( ceildiv "$cfs_quota" "$cfs_period" ) - [ "$ncpu" -gt 0 ] || return 1 - echo "$ncpu" -} - -get_quota_v2() { - cpuroot=$1 - ncpu=0 - [ -f "$cpuroot/cpu.max" ] || return 1 - cfs_quota=$( cut -d' ' -f 1 < "$cpuroot/cpu.max" ) - cfs_period=$( cut -d' ' -f 2 < "$cpuroot/cpu.max" ) - [ "$cfs_quota" = "max" ] && return 1 - [ "$cfs_period" = "0" ] && return 1 - ncpu=$( ceildiv "$cfs_quota" "$cfs_period" ) - [ "$ncpu" -gt 0 ] || return 1 - echo "$ncpu" -} - -get_cgroup_v1_path() { - needle=$1 - found= - foundroot= - mountpoint= - - [ -r "/proc/self/mountinfo" ] || return 1 - [ -r "/proc/self/cgroup" ] || return 1 - - while IFS= read -r line; do - case "$needle" in - "cpuset") - case "$line" in - *cpuset*) - found=$( echo "$line" | cut -d ' ' -f 4,5 ) - break - ;; - esac - ;; - "cpu") - case "$line" in - *cpuset*) - ;; - *cpu,cpuacct*|*cpuacct,cpu|*cpuacct*|*cpu*) - found=$( echo "$line" | cut -d ' ' -f 4,5 ) - break - ;; - esac - esac - done << __EOF__ -$( grep -F -- '- cgroup ' /proc/self/mountinfo ) -__EOF__ - - while IFS= read -r line; do - controller=$( echo "$line" | cut -d: -f 2 ) - case "$needle" in - "cpuset") - case "$controller" in - cpuset) - mountpoint=$( echo "$line" | cut -d: -f 3 ) - break - ;; - esac - ;; - "cpu") - case "$controller" in - cpu,cpuacct|cpuacct,cpu|cpuacct|cpu) - mountpoint=$( echo "$line" | cut -d: -f 3 ) - break - ;; - esac - ;; - esac -done << __EOF__ -$( grep -F -- 'cpu' /proc/self/cgroup ) -__EOF__ - - case "${found%% *}" in - "/") - foundroot="${found##* }$mountpoint" - ;; - "$mountpoint") - foundroot="${found##* }" - ;; - esac - echo "$foundroot" -} - -get_cgroup_v2_path() { - found= - foundroot= - mountpoint= - - [ -r "/proc/self/mountinfo" ] || return 1 - [ -r "/proc/self/cgroup" ] || return 1 - - while IFS= read -r line; do - found=$( echo "$line" | cut -d ' ' -f 4,5 ) - done << __EOF__ -$( grep -F -- '- cgroup2 ' /proc/self/mountinfo ) -__EOF__ - - while IFS= read -r line; do - mountpoint=$( echo "$line" | cut -d: -f 3 ) -done << __EOF__ -$( grep -F -- '0::' /proc/self/cgroup ) -__EOF__ - - case "${found%% *}" in - "") - return 1 - ;; - "/") - foundroot="${found##* }$mountpoint" - ;; - "$mountpoint") - foundroot="${found##* }" - ;; - esac - echo "$foundroot" -} - -ncpu_online=$( getconf _NPROCESSORS_ONLN ) -ncpu_cpuset= -ncpu_quota= -ncpu_cpuset_v2= -ncpu_quota_v2= - -cpuset=$( get_cgroup_v1_path "cpuset" ) && ncpu_cpuset=$( get_cpuset "$cpuset" "cpuset.effective_cpus" ) || ncpu_cpuset=$ncpu_online -cpu=$( get_cgroup_v1_path "cpu" ) && ncpu_quota=$( get_quota "$cpu" ) || ncpu_quota=$ncpu_online -cgroup_v2=$( get_cgroup_v2_path ) && ncpu_cpuset_v2=$( get_cpuset "$cgroup_v2" "cpuset.cpus.effective" ) || ncpu_cpuset_v2=$ncpu_online -cgroup_v2=$( get_cgroup_v2_path ) && ncpu_quota_v2=$( get_quota_v2 "$cgroup_v2" ) || ncpu_quota_v2=$ncpu_online - -ncpu=$( printf "%s\n%s\n%s\n%s\n%s\n" \ - "$ncpu_online" \ - "$ncpu_cpuset" \ - "$ncpu_quota" \ - "$ncpu_cpuset_v2" \ - "$ncpu_quota_v2" \ - | sort -n \ - | head -n 1 ) - -sed -i.bak -r 's/^(worker_processes)(.*)$/# Commented out by '"$ME"' on '"$(date)"'\n#\1\2\n\1 '"$ncpu"';/' /etc/nginx/nginx.conf diff --git a/stable/alpine/Dockerfile b/stable/alpine/Dockerfile index 5c79c9067..fb0c900a9 100644 --- a/stable/alpine/Dockerfile +++ b/stable/alpine/Dockerfile @@ -3,25 +3,19 @@ # # PLEASE DO NOT EDIT IT DIRECTLY. # -FROM alpine:3.16 +FROM nginx:1.28.0-alpine-slim -LABEL maintainer="NGINX Docker Maintainers " - -ENV NGINX_VERSION 1.22.0 -ENV NJS_VERSION 0.7.5 -ENV PKG_RELEASE 1 +ENV NJS_VERSION 0.8.10 +ENV NJS_RELEASE 1 RUN set -x \ -# create nginx user/group first, to be consistent throughout docker variants - && addgroup -g 101 -S nginx \ - && adduser -S -D -H -u 101 -h /var/cache/nginx -s /sbin/nologin -G nginx -g nginx nginx \ && apkArch="$(cat /etc/apk/arch)" \ && nginxPackages=" \ nginx=${NGINX_VERSION}-r${PKG_RELEASE} \ - nginx-module-xslt=${NGINX_VERSION}-r${PKG_RELEASE} \ - nginx-module-geoip=${NGINX_VERSION}-r${PKG_RELEASE} \ - nginx-module-image-filter=${NGINX_VERSION}-r${PKG_RELEASE} \ - nginx-module-njs=${NGINX_VERSION}.${NJS_VERSION}-r${PKG_RELEASE} \ + nginx-module-xslt=${NGINX_VERSION}-r${DYNPKG_RELEASE} \ + nginx-module-geoip=${NGINX_VERSION}-r${DYNPKG_RELEASE} \ + nginx-module-image-filter=${NGINX_VERSION}-r${DYNPKG_RELEASE} \ + nginx-module-njs=${NGINX_VERSION}.${NJS_VERSION}-r${NJS_RELEASE} \ " \ # install prerequisites for public key and pkg-oss checks && apk add --no-cache --virtual .checksum-deps \ @@ -29,17 +23,7 @@ RUN set -x \ && case "$apkArch" in \ x86_64|aarch64) \ # arches officially built by upstream - set -x \ - && KEY_SHA512="e7fa8303923d9b95db37a77ad46c68fd4755ff935d0a534d26eba83de193c76166c68bfe7f65471bf8881004ef4aa6df3e34689c305662750c0172fca5d8552a *stdin" \ - && wget -O /tmp/nginx_signing.rsa.pub https://nginx.org/keys/nginx_signing.rsa.pub \ - && if [ "$(openssl rsa -pubin -in /tmp/nginx_signing.rsa.pub -text -noout | openssl sha512 -r)" = "$KEY_SHA512" ]; then \ - echo "key verification succeeded!"; \ - mv /tmp/nginx_signing.rsa.pub /etc/apk/keys/; \ - else \ - echo "key verification failed!"; \ - exit 1; \ - fi \ - && apk add -X "https://nginx.org/packages/alpine/v$(egrep -o '^[0-9]+\.[0-9]+' /etc/alpine-release)/main" --no-cache $nginxPackages \ + apk add -X "https://nginx.org/packages/alpine/v$(egrep -o '^[0-9]+\.[0-9]+' /etc/alpine-release)/main" --no-cache $nginxPackages \ ;; \ *) \ # we're on an architecture upstream doesn't officially build for @@ -58,76 +42,38 @@ RUN set -x \ libxslt-dev \ gd-dev \ geoip-dev \ - perl-dev \ libedit-dev \ bash \ alpine-sdk \ findutils \ + curl \ && su nobody -s /bin/sh -c " \ export HOME=${tempDir} \ && cd ${tempDir} \ - && curl -f -O https://hg.nginx.org/pkg-oss/archive/714.tar.gz \ - && PKGOSSCHECKSUM=\"f457d5988c1f2663e04c5cdad71874c25e94754277dd9da5d73c1d37c32bdaf288b3b20d8b5d070ffb33aab363eaf4a7abbcf95fcfd72b0729a1c1908c37e30e *714.tar.gz\" \ - && if [ \"\$(openssl sha512 -r 714.tar.gz)\" = \"\$PKGOSSCHECKSUM\" ]; then \ + && curl -f -L -O https://github.com/nginx/pkg-oss/archive/${NGINX_VERSION}-${PKG_RELEASE}.tar.gz \ + && PKGOSSCHECKSUM=\"517bc18954ccf4efddd51986584ca1f37966833ad342a297e1fe58fd0faf14c5a4dabcb23519dca433878a2927a95d6bea05a6749ee2fa67a33bf24cdc41b1e4 *${NGINX_VERSION}-${PKG_RELEASE}.tar.gz\" \ + && if [ \"\$(openssl sha512 -r ${NGINX_VERSION}-${PKG_RELEASE}.tar.gz)\" = \"\$PKGOSSCHECKSUM\" ]; then \ echo \"pkg-oss tarball checksum verification succeeded!\"; \ else \ echo \"pkg-oss tarball checksum verification failed!\"; \ exit 1; \ fi \ - && tar xzvf 714.tar.gz \ - && cd pkg-oss-714 \ + && tar xzvf ${NGINX_VERSION}-${PKG_RELEASE}.tar.gz \ + && cd pkg-oss-${NGINX_VERSION}-${PKG_RELEASE} \ && cd alpine \ - && make all \ - && apk index -o ${tempDir}/packages/alpine/${apkArch}/APKINDEX.tar.gz ${tempDir}/packages/alpine/${apkArch}/*.apk \ + && make module-geoip module-image-filter module-njs module-xslt \ + && apk index --allow-untrusted -o ${tempDir}/packages/alpine/${apkArch}/APKINDEX.tar.gz ${tempDir}/packages/alpine/${apkArch}/*.apk \ && abuild-sign -k ${tempDir}/.abuild/abuild-key.rsa ${tempDir}/packages/alpine/${apkArch}/APKINDEX.tar.gz \ " \ && cp ${tempDir}/.abuild/abuild-key.rsa.pub /etc/apk/keys/ \ - && apk del .build-deps \ + && apk del --no-network .build-deps \ && apk add -X ${tempDir}/packages/alpine/ --no-cache $nginxPackages \ ;; \ esac \ # remove checksum deps - && apk del .checksum-deps \ + && apk del --no-network .checksum-deps \ # if we have leftovers from building, let's purge them (including extra, unnecessary build deps) && if [ -n "$tempDir" ]; then rm -rf "$tempDir"; fi \ - && if [ -n "/etc/apk/keys/abuild-key.rsa.pub" ]; then rm -f /etc/apk/keys/abuild-key.rsa.pub; fi \ - && if [ -n "/etc/apk/keys/nginx_signing.rsa.pub" ]; then rm -f /etc/apk/keys/nginx_signing.rsa.pub; fi \ -# Bring in gettext so we can get `envsubst`, then throw -# the rest away. To do this, we need to install `gettext` -# then move `envsubst` out of the way so `gettext` can -# be deleted completely, then move `envsubst` back. - && apk add --no-cache --virtual .gettext gettext \ - && mv /usr/bin/envsubst /tmp/ \ - \ - && runDeps="$( \ - scanelf --needed --nobanner /tmp/envsubst \ - | awk '{ gsub(/,/, "\nso:", $2); print "so:" $2 }' \ - | sort -u \ - | xargs -r apk info --installed \ - | sort -u \ - )" \ - && apk add --no-cache $runDeps \ - && apk del .gettext \ - && mv /tmp/envsubst /usr/local/bin/ \ -# Bring in tzdata so users could set the timezones through the environment -# variables - && apk add --no-cache tzdata \ + && if [ -f "/etc/apk/keys/abuild-key.rsa.pub" ]; then rm -f /etc/apk/keys/abuild-key.rsa.pub; fi \ # Bring in curl and ca-certificates to make registering on DNS SD easier - && apk add --no-cache curl ca-certificates \ -# forward request and error logs to docker log collector - && ln -sf /dev/stdout /var/log/nginx/access.log \ - && ln -sf /dev/stderr /var/log/nginx/error.log \ -# create a docker-entrypoint.d directory - && mkdir /docker-entrypoint.d - -COPY docker-entrypoint.sh / -COPY 10-listen-on-ipv6-by-default.sh /docker-entrypoint.d -COPY 20-envsubst-on-templates.sh /docker-entrypoint.d -COPY 30-tune-worker-processes.sh /docker-entrypoint.d -ENTRYPOINT ["/docker-entrypoint.sh"] - -EXPOSE 80 - -STOPSIGNAL SIGQUIT - -CMD ["nginx", "-g", "daemon off;"] + && apk add --no-cache curl ca-certificates diff --git a/stable/alpine/docker-entrypoint.sh b/stable/alpine/docker-entrypoint.sh deleted file mode 100755 index 72d5cd94e..000000000 --- a/stable/alpine/docker-entrypoint.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh -# vim:sw=4:ts=4:et - -set -e - -if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then - exec 3>&1 -else - exec 3>/dev/null -fi - -if [ "$1" = "nginx" -o "$1" = "nginx-debug" ]; then - if /usr/bin/find "/docker-entrypoint.d/" -mindepth 1 -maxdepth 1 -type f -print -quit 2>/dev/null | read v; then - echo >&3 "$0: /docker-entrypoint.d/ is not empty, will attempt to perform configuration" - - echo >&3 "$0: Looking for shell scripts in /docker-entrypoint.d/" - find "/docker-entrypoint.d/" -follow -type f -print | sort -V | while read -r f; do - case "$f" in - *.sh) - if [ -x "$f" ]; then - echo >&3 "$0: Launching $f"; - "$f" - else - # warn on shell scripts without exec bit - echo >&3 "$0: Ignoring $f, not executable"; - fi - ;; - *) echo >&3 "$0: Ignoring $f";; - esac - done - - echo >&3 "$0: Configuration complete; ready for start up" - else - echo >&3 "$0: No files found in /docker-entrypoint.d/, skipping configuration" - fi -fi - -exec "$@" diff --git a/stable/debian-otel/Dockerfile b/stable/debian-otel/Dockerfile new file mode 100644 index 000000000..e4129a437 --- /dev/null +++ b/stable/debian-otel/Dockerfile @@ -0,0 +1,100 @@ +# +# NOTE: THIS DOCKERFILE IS GENERATED VIA "update.sh" +# +# PLEASE DO NOT EDIT IT DIRECTLY. +# +FROM nginx:1.28.0 + +ENV OTEL_VERSION 0.1.2 + +RUN set -x; \ + NGINX_GPGKEY_PATH=/etc/apt/keyrings/nginx-archive-keyring.gpg; \ + dpkgArch="$(dpkg --print-architecture)" \ + && nginxPackages=" \ + nginx=${NGINX_VERSION}-${PKG_RELEASE} \ + nginx-module-xslt=${NGINX_VERSION}-${DYNPKG_RELEASE} \ + nginx-module-geoip=${NGINX_VERSION}-${DYNPKG_RELEASE} \ + nginx-module-image-filter=${NGINX_VERSION}-${DYNPKG_RELEASE} \ + nginx-module-njs=${NGINX_VERSION}+${NJS_VERSION}-${NJS_RELEASE} \ + nginx-module-otel=${NGINX_VERSION}+${OTEL_VERSION}-${PKG_RELEASE} \ + " \ + && case "$dpkgArch" in \ + amd64|arm64) \ +# arches officialy built by upstream + echo "deb [signed-by=$NGINX_GPGKEY_PATH] https://nginx.org/packages/debian/ bookworm nginx" >> /etc/apt/sources.list.d/nginx.list \ + && apt-get update \ + ;; \ + *) \ +# we're on an architecture upstream doesn't officially build for +# let's build binaries from the published packaging sources +# new directory for storing sources and .deb files + tempDir="$(mktemp -d)" \ + && chmod 777 "$tempDir" \ +# (777 to ensure APT's "_apt" user can access it too) + \ +# save list of currently-installed packages so build dependencies can be cleanly removed later + && savedAptMark="$(apt-mark showmanual)" \ + \ +# build .deb files from upstream's packaging sources + && apt-get update \ + && apt-get install --no-install-recommends --no-install-suggests -y \ + curl \ + devscripts \ + equivs \ + git \ + libxml2-utils \ + lsb-release \ + xsltproc \ + && ( \ + cd "$tempDir" \ + && REVISION="${NGINX_VERSION}-${PKG_RELEASE}" \ + && REVISION=${REVISION%~*} \ + && curl -f -L -O https://github.com/nginx/pkg-oss/archive/${REVISION}.tar.gz \ + && PKGOSSCHECKSUM="517bc18954ccf4efddd51986584ca1f37966833ad342a297e1fe58fd0faf14c5a4dabcb23519dca433878a2927a95d6bea05a6749ee2fa67a33bf24cdc41b1e4 *${REVISION}.tar.gz" \ + && if [ "$(openssl sha512 -r ${REVISION}.tar.gz)" = "$PKGOSSCHECKSUM" ]; then \ + echo "pkg-oss tarball checksum verification succeeded!"; \ + else \ + echo "pkg-oss tarball checksum verification failed!"; \ + exit 1; \ + fi \ + && tar xzvf ${REVISION}.tar.gz \ + && cd pkg-oss-${REVISION} \ + && cd debian \ + && for target in module-otel; do \ + make rules-$target; \ + mk-build-deps --install --tool="apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends --yes" \ + debuild-$target/nginx-$NGINX_VERSION/debian/control; \ + done \ + && make module-otel \ + ) \ +# we don't remove APT lists here because they get re-downloaded and removed later + \ +# reset apt-mark's "manual" list so that "purge --auto-remove" will remove all build dependencies +# (which is done after we install the built packages so we don't have to redownload any overlapping dependencies) + && apt-mark showmanual | xargs apt-mark auto > /dev/null \ + && { [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; } \ + \ +# create a temporary local APT repo to install from (so that dependency resolution can be handled by APT, as it should be) + && ls -lAFh "$tempDir" \ + && ( cd "$tempDir" && dpkg-scanpackages . > Packages ) \ + && grep '^Package: ' "$tempDir/Packages" \ + && echo "deb [ trusted=yes ] file://$tempDir ./" > /etc/apt/sources.list.d/temp.list \ +# work around the following APT issue by using "Acquire::GzipIndexes=false" (overriding "/etc/apt/apt.conf.d/docker-gzip-indexes") +# Could not open file /var/lib/apt/lists/partial/_tmp_tmp.ODWljpQfkE_._Packages - open (13: Permission denied) +# ... +# E: Failed to fetch store:/var/lib/apt/lists/partial/_tmp_tmp.ODWljpQfkE_._Packages Could not open file /var/lib/apt/lists/partial/_tmp_tmp.ODWljpQfkE_._Packages - open (13: Permission denied) + && apt-get -o Acquire::GzipIndexes=false update \ + ;; \ + esac \ + \ + && apt-get install --no-install-recommends --no-install-suggests -y \ + $nginxPackages \ + gettext-base \ + curl \ + && apt-get remove --purge --auto-remove -y && rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/nginx.list \ + \ +# if we have leftovers from building, let's purge them (including extra, unnecessary build deps) + && if [ -n "$tempDir" ]; then \ + apt-get purge -y --auto-remove \ + && rm -rf "$tempDir" /etc/apt/sources.list.d/temp.list; \ + fi diff --git a/stable/debian-perl/10-listen-on-ipv6-by-default.sh b/stable/debian-perl/10-listen-on-ipv6-by-default.sh deleted file mode 100755 index 9585152ba..000000000 --- a/stable/debian-perl/10-listen-on-ipv6-by-default.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/bin/sh -# vim:sw=4:ts=4:et - -set -e - -ME=$(basename $0) -DEFAULT_CONF_FILE="etc/nginx/conf.d/default.conf" - -# check if we have ipv6 available -if [ ! -f "/proc/net/if_inet6" ]; then - echo >&3 "$ME: info: ipv6 not available" - exit 0 -fi - -if [ ! -f "/$DEFAULT_CONF_FILE" ]; then - echo >&3 "$ME: info: /$DEFAULT_CONF_FILE is not a file or does not exist" - exit 0 -fi - -# check if the file can be modified, e.g. not on a r/o filesystem -touch /$DEFAULT_CONF_FILE 2>/dev/null || { echo >&3 "$ME: info: can not modify /$DEFAULT_CONF_FILE (read-only file system?)"; exit 0; } - -# check if the file is already modified, e.g. on a container restart -grep -q "listen \[::]\:80;" /$DEFAULT_CONF_FILE && { echo >&3 "$ME: info: IPv6 listen already enabled"; exit 0; } - -if [ -f "/etc/os-release" ]; then - . /etc/os-release -else - echo >&3 "$ME: info: can not guess the operating system" - exit 0 -fi - -echo >&3 "$ME: info: Getting the checksum of /$DEFAULT_CONF_FILE" - -case "$ID" in - "debian") - CHECKSUM=$(dpkg-query --show --showformat='${Conffiles}\n' nginx | grep $DEFAULT_CONF_FILE | cut -d' ' -f 3) - echo "$CHECKSUM /$DEFAULT_CONF_FILE" | md5sum -c - >/dev/null 2>&1 || { - echo >&3 "$ME: info: /$DEFAULT_CONF_FILE differs from the packaged version" - exit 0 - } - ;; - "alpine") - CHECKSUM=$(apk manifest nginx 2>/dev/null| grep $DEFAULT_CONF_FILE | cut -d' ' -f 1 | cut -d ':' -f 2) - echo "$CHECKSUM /$DEFAULT_CONF_FILE" | sha1sum -c - >/dev/null 2>&1 || { - echo >&3 "$ME: info: /$DEFAULT_CONF_FILE differs from the packaged version" - exit 0 - } - ;; - *) - echo >&3 "$ME: info: Unsupported distribution" - exit 0 - ;; -esac - -# enable ipv6 on default.conf listen sockets -sed -i -E 's,listen 80;,listen 80;\n listen [::]:80;,' /$DEFAULT_CONF_FILE - -echo >&3 "$ME: info: Enabled listen on IPv6 in /$DEFAULT_CONF_FILE" - -exit 0 diff --git a/stable/debian-perl/20-envsubst-on-templates.sh b/stable/debian-perl/20-envsubst-on-templates.sh deleted file mode 100755 index 4f330295b..000000000 --- a/stable/debian-perl/20-envsubst-on-templates.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/sh - -set -e - -ME=$(basename $0) - -auto_envsubst() { - local template_dir="${NGINX_ENVSUBST_TEMPLATE_DIR:-/etc/nginx/templates}" - local suffix="${NGINX_ENVSUBST_TEMPLATE_SUFFIX:-.template}" - local output_dir="${NGINX_ENVSUBST_OUTPUT_DIR:-/etc/nginx/conf.d}" - - local template defined_envs relative_path output_path subdir - defined_envs=$(printf '${%s} ' $(env | cut -d= -f1)) - [ -d "$template_dir" ] || return 0 - if [ ! -w "$output_dir" ]; then - echo >&3 "$ME: ERROR: $template_dir exists, but $output_dir is not writable" - return 0 - fi - find "$template_dir" -follow -type f -name "*$suffix" -print | while read -r template; do - relative_path="${template#$template_dir/}" - output_path="$output_dir/${relative_path%$suffix}" - subdir=$(dirname "$relative_path") - # create a subdirectory where the template file exists - mkdir -p "$output_dir/$subdir" - echo >&3 "$ME: Running envsubst on $template to $output_path" - envsubst "$defined_envs" < "$template" > "$output_path" - done -} - -auto_envsubst - -exit 0 diff --git a/stable/debian-perl/30-tune-worker-processes.sh b/stable/debian-perl/30-tune-worker-processes.sh deleted file mode 100755 index 565058715..000000000 --- a/stable/debian-perl/30-tune-worker-processes.sh +++ /dev/null @@ -1,188 +0,0 @@ -#!/bin/sh -# vim:sw=2:ts=2:sts=2:et - -set -eu - -LC_ALL=C -ME=$( basename "$0" ) -PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin - -[ "${NGINX_ENTRYPOINT_WORKER_PROCESSES_AUTOTUNE:-}" ] || exit 0 - -touch /etc/nginx/nginx.conf 2>/dev/null || { echo >&2 "$ME: error: can not modify /etc/nginx/nginx.conf (read-only file system?)"; exit 0; } - -ceildiv() { - num=$1 - div=$2 - echo $(( (num + div - 1) / div )) -} - -get_cpuset() { - cpusetroot=$1 - cpusetfile=$2 - ncpu=0 - [ -f "$cpusetroot/$cpusetfile" ] || return 1 - for token in $( tr ',' ' ' < "$cpusetroot/$cpusetfile" ); do - case "$token" in - *-*) - count=$( seq $(echo "$token" | tr '-' ' ') | wc -l ) - ncpu=$(( ncpu+count )) - ;; - *) - ncpu=$(( ncpu+1 )) - ;; - esac - done - echo "$ncpu" -} - -get_quota() { - cpuroot=$1 - ncpu=0 - [ -f "$cpuroot/cpu.cfs_quota_us" ] || return 1 - [ -f "$cpuroot/cpu.cfs_period_us" ] || return 1 - cfs_quota=$( cat "$cpuroot/cpu.cfs_quota_us" ) - cfs_period=$( cat "$cpuroot/cpu.cfs_period_us" ) - [ "$cfs_quota" = "-1" ] && return 1 - [ "$cfs_period" = "0" ] && return 1 - ncpu=$( ceildiv "$cfs_quota" "$cfs_period" ) - [ "$ncpu" -gt 0 ] || return 1 - echo "$ncpu" -} - -get_quota_v2() { - cpuroot=$1 - ncpu=0 - [ -f "$cpuroot/cpu.max" ] || return 1 - cfs_quota=$( cut -d' ' -f 1 < "$cpuroot/cpu.max" ) - cfs_period=$( cut -d' ' -f 2 < "$cpuroot/cpu.max" ) - [ "$cfs_quota" = "max" ] && return 1 - [ "$cfs_period" = "0" ] && return 1 - ncpu=$( ceildiv "$cfs_quota" "$cfs_period" ) - [ "$ncpu" -gt 0 ] || return 1 - echo "$ncpu" -} - -get_cgroup_v1_path() { - needle=$1 - found= - foundroot= - mountpoint= - - [ -r "/proc/self/mountinfo" ] || return 1 - [ -r "/proc/self/cgroup" ] || return 1 - - while IFS= read -r line; do - case "$needle" in - "cpuset") - case "$line" in - *cpuset*) - found=$( echo "$line" | cut -d ' ' -f 4,5 ) - break - ;; - esac - ;; - "cpu") - case "$line" in - *cpuset*) - ;; - *cpu,cpuacct*|*cpuacct,cpu|*cpuacct*|*cpu*) - found=$( echo "$line" | cut -d ' ' -f 4,5 ) - break - ;; - esac - esac - done << __EOF__ -$( grep -F -- '- cgroup ' /proc/self/mountinfo ) -__EOF__ - - while IFS= read -r line; do - controller=$( echo "$line" | cut -d: -f 2 ) - case "$needle" in - "cpuset") - case "$controller" in - cpuset) - mountpoint=$( echo "$line" | cut -d: -f 3 ) - break - ;; - esac - ;; - "cpu") - case "$controller" in - cpu,cpuacct|cpuacct,cpu|cpuacct|cpu) - mountpoint=$( echo "$line" | cut -d: -f 3 ) - break - ;; - esac - ;; - esac -done << __EOF__ -$( grep -F -- 'cpu' /proc/self/cgroup ) -__EOF__ - - case "${found%% *}" in - "/") - foundroot="${found##* }$mountpoint" - ;; - "$mountpoint") - foundroot="${found##* }" - ;; - esac - echo "$foundroot" -} - -get_cgroup_v2_path() { - found= - foundroot= - mountpoint= - - [ -r "/proc/self/mountinfo" ] || return 1 - [ -r "/proc/self/cgroup" ] || return 1 - - while IFS= read -r line; do - found=$( echo "$line" | cut -d ' ' -f 4,5 ) - done << __EOF__ -$( grep -F -- '- cgroup2 ' /proc/self/mountinfo ) -__EOF__ - - while IFS= read -r line; do - mountpoint=$( echo "$line" | cut -d: -f 3 ) -done << __EOF__ -$( grep -F -- '0::' /proc/self/cgroup ) -__EOF__ - - case "${found%% *}" in - "") - return 1 - ;; - "/") - foundroot="${found##* }$mountpoint" - ;; - "$mountpoint") - foundroot="${found##* }" - ;; - esac - echo "$foundroot" -} - -ncpu_online=$( getconf _NPROCESSORS_ONLN ) -ncpu_cpuset= -ncpu_quota= -ncpu_cpuset_v2= -ncpu_quota_v2= - -cpuset=$( get_cgroup_v1_path "cpuset" ) && ncpu_cpuset=$( get_cpuset "$cpuset" "cpuset.effective_cpus" ) || ncpu_cpuset=$ncpu_online -cpu=$( get_cgroup_v1_path "cpu" ) && ncpu_quota=$( get_quota "$cpu" ) || ncpu_quota=$ncpu_online -cgroup_v2=$( get_cgroup_v2_path ) && ncpu_cpuset_v2=$( get_cpuset "$cgroup_v2" "cpuset.cpus.effective" ) || ncpu_cpuset_v2=$ncpu_online -cgroup_v2=$( get_cgroup_v2_path ) && ncpu_quota_v2=$( get_quota_v2 "$cgroup_v2" ) || ncpu_quota_v2=$ncpu_online - -ncpu=$( printf "%s\n%s\n%s\n%s\n%s\n" \ - "$ncpu_online" \ - "$ncpu_cpuset" \ - "$ncpu_quota" \ - "$ncpu_cpuset_v2" \ - "$ncpu_quota_v2" \ - | sort -n \ - | head -n 1 ) - -sed -i.bak -r 's/^(worker_processes)(.*)$/# Commented out by '"$ME"' on '"$(date)"'\n#\1\2\n\1 '"$ncpu"';/' /etc/nginx/nginx.conf diff --git a/stable/debian-perl/Dockerfile b/stable/debian-perl/Dockerfile index 57d8a670f..bda0e1b84 100644 --- a/stable/debian-perl/Dockerfile +++ b/stable/debian-perl/Dockerfile @@ -3,67 +3,67 @@ # # PLEASE DO NOT EDIT IT DIRECTLY. # -FROM debian:bullseye-slim +FROM nginx:1.28.0 -LABEL maintainer="NGINX Docker Maintainers " - -ENV NGINX_VERSION 1.22.0 -ENV NJS_VERSION 0.7.5 -ENV PKG_RELEASE 1~bullseye - -RUN set -x \ -# create nginx user/group first, to be consistent throughout docker variants - && addgroup --system --gid 101 nginx \ - && adduser --system --disabled-login --ingroup nginx --no-create-home --home /nonexistent --gecos "nginx user" --shell /bin/false --uid 101 nginx \ - && apt-get update \ - && apt-get install --no-install-recommends --no-install-suggests -y gnupg1 ca-certificates \ - && \ - NGINX_GPGKEY=573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62; \ - found=''; \ - for server in \ - hkp://keyserver.ubuntu.com:80 \ - pgp.mit.edu \ - ; do \ - echo "Fetching GPG key $NGINX_GPGKEY from $server"; \ - apt-key adv --keyserver "$server" --keyserver-options timeout=10 --recv-keys "$NGINX_GPGKEY" && found=yes && break; \ - done; \ - test -z "$found" && echo >&2 "error: failed to fetch GPG key $NGINX_GPGKEY" && exit 1; \ - apt-get remove --purge --auto-remove -y gnupg1 && rm -rf /var/lib/apt/lists/* \ - && dpkgArch="$(dpkg --print-architecture)" \ +RUN set -x; \ + NGINX_GPGKEY_PATH=/etc/apt/keyrings/nginx-archive-keyring.gpg; \ + dpkgArch="$(dpkg --print-architecture)" \ && nginxPackages=" \ nginx=${NGINX_VERSION}-${PKG_RELEASE} \ - nginx-module-xslt=${NGINX_VERSION}-${PKG_RELEASE} \ - nginx-module-geoip=${NGINX_VERSION}-${PKG_RELEASE} \ - nginx-module-image-filter=${NGINX_VERSION}-${PKG_RELEASE} \ - nginx-module-perl=${NGINX_VERSION}-${PKG_RELEASE} \ - nginx-module-njs=${NGINX_VERSION}+${NJS_VERSION}-${PKG_RELEASE} \ + nginx-module-xslt=${NGINX_VERSION}-${DYNPKG_RELEASE} \ + nginx-module-geoip=${NGINX_VERSION}-${DYNPKG_RELEASE} \ + nginx-module-image-filter=${NGINX_VERSION}-${DYNPKG_RELEASE} \ + nginx-module-perl=${NGINX_VERSION}-${DYNPKG_RELEASE} \ + nginx-module-njs=${NGINX_VERSION}+${NJS_VERSION}-${NJS_RELEASE} \ " \ && case "$dpkgArch" in \ amd64|arm64) \ # arches officialy built by upstream - echo "deb https://nginx.org/packages/debian/ bullseye nginx" >> /etc/apt/sources.list.d/nginx.list \ + echo "deb [signed-by=$NGINX_GPGKEY_PATH] https://nginx.org/packages/debian/ bookworm nginx" >> /etc/apt/sources.list.d/nginx.list \ && apt-get update \ ;; \ *) \ # we're on an architecture upstream doesn't officially build for -# let's build binaries from the published source packages - echo "deb-src https://nginx.org/packages/debian/ bullseye nginx" >> /etc/apt/sources.list.d/nginx.list \ - \ +# let's build binaries from the published packaging sources # new directory for storing sources and .deb files - && tempDir="$(mktemp -d)" \ + tempDir="$(mktemp -d)" \ && chmod 777 "$tempDir" \ # (777 to ensure APT's "_apt" user can access it too) \ # save list of currently-installed packages so build dependencies can be cleanly removed later && savedAptMark="$(apt-mark showmanual)" \ \ -# build .deb files from upstream's source packages (which are verified by apt-get) +# build .deb files from upstream's packaging sources && apt-get update \ - && apt-get build-dep -y $nginxPackages \ + && apt-get install --no-install-recommends --no-install-suggests -y \ + curl \ + devscripts \ + equivs \ + git \ + libxml2-utils \ + lsb-release \ + xsltproc \ && ( \ cd "$tempDir" \ - && DEB_BUILD_OPTIONS="nocheck parallel=$(nproc)" \ - apt-get source --compile $nginxPackages \ + && REVISION="${NGINX_VERSION}-${PKG_RELEASE}" \ + && REVISION=${REVISION%~*} \ + && curl -f -L -O https://github.com/nginx/pkg-oss/archive/${REVISION}.tar.gz \ + && PKGOSSCHECKSUM="517bc18954ccf4efddd51986584ca1f37966833ad342a297e1fe58fd0faf14c5a4dabcb23519dca433878a2927a95d6bea05a6749ee2fa67a33bf24cdc41b1e4 *${REVISION}.tar.gz" \ + && if [ "$(openssl sha512 -r ${REVISION}.tar.gz)" = "$PKGOSSCHECKSUM" ]; then \ + echo "pkg-oss tarball checksum verification succeeded!"; \ + else \ + echo "pkg-oss tarball checksum verification failed!"; \ + exit 1; \ + fi \ + && tar xzvf ${REVISION}.tar.gz \ + && cd pkg-oss-${REVISION} \ + && cd debian \ + && for target in module-perl; do \ + make rules-$target; \ + mk-build-deps --install --tool="apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends --yes" \ + debuild-$target/nginx-$NGINX_VERSION/debian/control; \ + done \ + && make module-perl \ ) \ # we don't remove APT lists here because they get re-downloaded and removed later \ @@ -95,21 +95,4 @@ RUN set -x \ && if [ -n "$tempDir" ]; then \ apt-get purge -y --auto-remove \ && rm -rf "$tempDir" /etc/apt/sources.list.d/temp.list; \ - fi \ -# forward request and error logs to docker log collector - && ln -sf /dev/stdout /var/log/nginx/access.log \ - && ln -sf /dev/stderr /var/log/nginx/error.log \ -# create a docker-entrypoint.d directory - && mkdir /docker-entrypoint.d - -COPY docker-entrypoint.sh / -COPY 10-listen-on-ipv6-by-default.sh /docker-entrypoint.d -COPY 20-envsubst-on-templates.sh /docker-entrypoint.d -COPY 30-tune-worker-processes.sh /docker-entrypoint.d -ENTRYPOINT ["/docker-entrypoint.sh"] - -EXPOSE 80 - -STOPSIGNAL SIGQUIT - -CMD ["nginx", "-g", "daemon off;"] + fi diff --git a/stable/debian-perl/docker-entrypoint.sh b/stable/debian-perl/docker-entrypoint.sh deleted file mode 100755 index 72d5cd94e..000000000 --- a/stable/debian-perl/docker-entrypoint.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh -# vim:sw=4:ts=4:et - -set -e - -if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then - exec 3>&1 -else - exec 3>/dev/null -fi - -if [ "$1" = "nginx" -o "$1" = "nginx-debug" ]; then - if /usr/bin/find "/docker-entrypoint.d/" -mindepth 1 -maxdepth 1 -type f -print -quit 2>/dev/null | read v; then - echo >&3 "$0: /docker-entrypoint.d/ is not empty, will attempt to perform configuration" - - echo >&3 "$0: Looking for shell scripts in /docker-entrypoint.d/" - find "/docker-entrypoint.d/" -follow -type f -print | sort -V | while read -r f; do - case "$f" in - *.sh) - if [ -x "$f" ]; then - echo >&3 "$0: Launching $f"; - "$f" - else - # warn on shell scripts without exec bit - echo >&3 "$0: Ignoring $f, not executable"; - fi - ;; - *) echo >&3 "$0: Ignoring $f";; - esac - done - - echo >&3 "$0: Configuration complete; ready for start up" - else - echo >&3 "$0: No files found in /docker-entrypoint.d/, skipping configuration" - fi -fi - -exec "$@" diff --git a/stable/debian/10-listen-on-ipv6-by-default.sh b/stable/debian/10-listen-on-ipv6-by-default.sh index 9585152ba..61a901dee 100755 --- a/stable/debian/10-listen-on-ipv6-by-default.sh +++ b/stable/debian/10-listen-on-ipv6-by-default.sh @@ -3,52 +3,58 @@ set -e -ME=$(basename $0) +entrypoint_log() { + if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then + echo "$@" + fi +} + +ME=$(basename "$0") DEFAULT_CONF_FILE="etc/nginx/conf.d/default.conf" # check if we have ipv6 available if [ ! -f "/proc/net/if_inet6" ]; then - echo >&3 "$ME: info: ipv6 not available" + entrypoint_log "$ME: info: ipv6 not available" exit 0 fi if [ ! -f "/$DEFAULT_CONF_FILE" ]; then - echo >&3 "$ME: info: /$DEFAULT_CONF_FILE is not a file or does not exist" + entrypoint_log "$ME: info: /$DEFAULT_CONF_FILE is not a file or does not exist" exit 0 fi # check if the file can be modified, e.g. not on a r/o filesystem -touch /$DEFAULT_CONF_FILE 2>/dev/null || { echo >&3 "$ME: info: can not modify /$DEFAULT_CONF_FILE (read-only file system?)"; exit 0; } +touch /$DEFAULT_CONF_FILE 2>/dev/null || { entrypoint_log "$ME: info: can not modify /$DEFAULT_CONF_FILE (read-only file system?)"; exit 0; } # check if the file is already modified, e.g. on a container restart -grep -q "listen \[::]\:80;" /$DEFAULT_CONF_FILE && { echo >&3 "$ME: info: IPv6 listen already enabled"; exit 0; } +grep -q "listen \[::\]:80;" /$DEFAULT_CONF_FILE && { entrypoint_log "$ME: info: IPv6 listen already enabled"; exit 0; } if [ -f "/etc/os-release" ]; then . /etc/os-release else - echo >&3 "$ME: info: can not guess the operating system" + entrypoint_log "$ME: info: can not guess the operating system" exit 0 fi -echo >&3 "$ME: info: Getting the checksum of /$DEFAULT_CONF_FILE" +entrypoint_log "$ME: info: Getting the checksum of /$DEFAULT_CONF_FILE" case "$ID" in "debian") CHECKSUM=$(dpkg-query --show --showformat='${Conffiles}\n' nginx | grep $DEFAULT_CONF_FILE | cut -d' ' -f 3) echo "$CHECKSUM /$DEFAULT_CONF_FILE" | md5sum -c - >/dev/null 2>&1 || { - echo >&3 "$ME: info: /$DEFAULT_CONF_FILE differs from the packaged version" + entrypoint_log "$ME: info: /$DEFAULT_CONF_FILE differs from the packaged version" exit 0 } ;; "alpine") CHECKSUM=$(apk manifest nginx 2>/dev/null| grep $DEFAULT_CONF_FILE | cut -d' ' -f 1 | cut -d ':' -f 2) echo "$CHECKSUM /$DEFAULT_CONF_FILE" | sha1sum -c - >/dev/null 2>&1 || { - echo >&3 "$ME: info: /$DEFAULT_CONF_FILE differs from the packaged version" + entrypoint_log "$ME: info: /$DEFAULT_CONF_FILE differs from the packaged version" exit 0 } ;; *) - echo >&3 "$ME: info: Unsupported distribution" + entrypoint_log "$ME: info: Unsupported distribution" exit 0 ;; esac @@ -56,6 +62,6 @@ esac # enable ipv6 on default.conf listen sockets sed -i -E 's,listen 80;,listen 80;\n listen [::]:80;,' /$DEFAULT_CONF_FILE -echo >&3 "$ME: info: Enabled listen on IPv6 in /$DEFAULT_CONF_FILE" +entrypoint_log "$ME: info: Enabled listen on IPv6 in /$DEFAULT_CONF_FILE" exit 0 diff --git a/stable/debian/15-local-resolvers.envsh b/stable/debian/15-local-resolvers.envsh new file mode 100755 index 000000000..e830ddacd --- /dev/null +++ b/stable/debian/15-local-resolvers.envsh @@ -0,0 +1,15 @@ +#!/bin/sh +# vim:sw=2:ts=2:sts=2:et + +set -eu + +LC_ALL=C +PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin + +[ "${NGINX_ENTRYPOINT_LOCAL_RESOLVERS:-}" ] || return 0 + +NGINX_LOCAL_RESOLVERS=$(awk 'BEGIN{ORS=" "} $1=="nameserver" {if ($2 ~ ":") {print "["$2"]"} else {print $2}}' /etc/resolv.conf) + +NGINX_LOCAL_RESOLVERS="${NGINX_LOCAL_RESOLVERS% }" + +export NGINX_LOCAL_RESOLVERS diff --git a/stable/debian/20-envsubst-on-templates.sh b/stable/debian/20-envsubst-on-templates.sh index 4f330295b..3804165c9 100755 --- a/stable/debian/20-envsubst-on-templates.sh +++ b/stable/debian/20-envsubst-on-templates.sh @@ -2,29 +2,75 @@ set -e -ME=$(basename $0) +ME=$(basename "$0") + +entrypoint_log() { + if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then + echo "$@" + fi +} + +add_stream_block() { + local conffile="/etc/nginx/nginx.conf" + + if grep -q -E "\s*stream\s*\{" "$conffile"; then + entrypoint_log "$ME: $conffile contains a stream block; include $stream_output_dir/*.conf to enable stream templates" + else + # check if the file can be modified, e.g. not on a r/o filesystem + touch "$conffile" 2>/dev/null || { entrypoint_log "$ME: info: can not modify $conffile (read-only file system?)"; exit 0; } + entrypoint_log "$ME: Appending stream block to $conffile to include $stream_output_dir/*.conf" + cat << END >> "$conffile" +# added by "$ME" on "$(date)" +stream { + include $stream_output_dir/*.conf; +} +END + fi +} auto_envsubst() { local template_dir="${NGINX_ENVSUBST_TEMPLATE_DIR:-/etc/nginx/templates}" local suffix="${NGINX_ENVSUBST_TEMPLATE_SUFFIX:-.template}" local output_dir="${NGINX_ENVSUBST_OUTPUT_DIR:-/etc/nginx/conf.d}" + local stream_suffix="${NGINX_ENVSUBST_STREAM_TEMPLATE_SUFFIX:-.stream-template}" + local stream_output_dir="${NGINX_ENVSUBST_STREAM_OUTPUT_DIR:-/etc/nginx/stream-conf.d}" + local filter="${NGINX_ENVSUBST_FILTER:-}" local template defined_envs relative_path output_path subdir - defined_envs=$(printf '${%s} ' $(env | cut -d= -f1)) + defined_envs=$(printf '${%s} ' $(awk "END { for (name in ENVIRON) { print ( name ~ /${filter}/ ) ? name : \"\" } }" < /dev/null )) [ -d "$template_dir" ] || return 0 if [ ! -w "$output_dir" ]; then - echo >&3 "$ME: ERROR: $template_dir exists, but $output_dir is not writable" + entrypoint_log "$ME: ERROR: $template_dir exists, but $output_dir is not writable" return 0 fi find "$template_dir" -follow -type f -name "*$suffix" -print | while read -r template; do - relative_path="${template#$template_dir/}" - output_path="$output_dir/${relative_path%$suffix}" + relative_path="${template#"$template_dir/"}" + output_path="$output_dir/${relative_path%"$suffix"}" subdir=$(dirname "$relative_path") # create a subdirectory where the template file exists mkdir -p "$output_dir/$subdir" - echo >&3 "$ME: Running envsubst on $template to $output_path" + entrypoint_log "$ME: Running envsubst on $template to $output_path" envsubst "$defined_envs" < "$template" > "$output_path" done + + # Print the first file with the stream suffix, this will be false if there are none + if test -n "$(find "$template_dir" -name "*$stream_suffix" -print -quit)"; then + mkdir -p "$stream_output_dir" + if [ ! -w "$stream_output_dir" ]; then + entrypoint_log "$ME: ERROR: $template_dir exists, but $stream_output_dir is not writable" + return 0 + fi + add_stream_block + find "$template_dir" -follow -type f -name "*$stream_suffix" -print | while read -r template; do + relative_path="${template#"$template_dir/"}" + output_path="$stream_output_dir/${relative_path%"$stream_suffix"}" + subdir=$(dirname "$relative_path") + # create a subdirectory where the template file exists + mkdir -p "$stream_output_dir/$subdir" + entrypoint_log "$ME: Running envsubst on $template to $output_path" + envsubst "$defined_envs" < "$template" > "$output_path" + done + fi } auto_envsubst diff --git a/stable/debian/30-tune-worker-processes.sh b/stable/debian/30-tune-worker-processes.sh index 565058715..defb994f3 100755 --- a/stable/debian/30-tune-worker-processes.sh +++ b/stable/debian/30-tune-worker-processes.sh @@ -4,7 +4,7 @@ set -eu LC_ALL=C -ME=$( basename "$0" ) +ME=$(basename "$0") PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin [ "${NGINX_ENTRYPOINT_WORKER_PROCESSES_AUTOTUNE:-}" ] || exit 0 @@ -158,7 +158,7 @@ __EOF__ "/") foundroot="${found##* }$mountpoint" ;; - "$mountpoint") + "$mountpoint" | /../*) foundroot="${found##* }" ;; esac diff --git a/stable/debian/Dockerfile b/stable/debian/Dockerfile index 12eecb65a..99f34952d 100644 --- a/stable/debian/Dockerfile +++ b/stable/debian/Dockerfile @@ -3,66 +3,96 @@ # # PLEASE DO NOT EDIT IT DIRECTLY. # -FROM debian:bullseye-slim +FROM debian:bookworm-slim LABEL maintainer="NGINX Docker Maintainers " -ENV NGINX_VERSION 1.22.0 -ENV NJS_VERSION 0.7.5 -ENV PKG_RELEASE 1~bullseye +ENV NGINX_VERSION 1.28.0 +ENV NJS_VERSION 0.8.10 +ENV NJS_RELEASE 1~bookworm +ENV PKG_RELEASE 1~bookworm +ENV DYNPKG_RELEASE 1~bookworm RUN set -x \ # create nginx user/group first, to be consistent throughout docker variants - && addgroup --system --gid 101 nginx \ - && adduser --system --disabled-login --ingroup nginx --no-create-home --home /nonexistent --gecos "nginx user" --shell /bin/false --uid 101 nginx \ + && groupadd --system --gid 101 nginx \ + && useradd --system --gid nginx --no-create-home --home /nonexistent --comment "nginx user" --shell /bin/false --uid 101 nginx \ && apt-get update \ && apt-get install --no-install-recommends --no-install-suggests -y gnupg1 ca-certificates \ && \ - NGINX_GPGKEY=573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62; \ + NGINX_GPGKEYS="573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 8540A6F18833A80E9C1653A42FD21310B49F6B46 9E9BE90EACBCDE69FE9B204CBCDCD8A38D88A2B3"; \ + NGINX_GPGKEY_PATH=/etc/apt/keyrings/nginx-archive-keyring.gpg; \ + export GNUPGHOME="$(mktemp -d)"; \ found=''; \ + for NGINX_GPGKEY in $NGINX_GPGKEYS; do \ for server in \ hkp://keyserver.ubuntu.com:80 \ pgp.mit.edu \ ; do \ echo "Fetching GPG key $NGINX_GPGKEY from $server"; \ - apt-key adv --keyserver "$server" --keyserver-options timeout=10 --recv-keys "$NGINX_GPGKEY" && found=yes && break; \ + gpg1 --batch --keyserver "$server" --keyserver-options timeout=10 --recv-keys "$NGINX_GPGKEY" && found=yes && break; \ done; \ test -z "$found" && echo >&2 "error: failed to fetch GPG key $NGINX_GPGKEY" && exit 1; \ + done; \ + gpg1 --batch --export $NGINX_GPGKEYS > "$NGINX_GPGKEY_PATH" ; \ + rm -rf "$GNUPGHOME"; \ apt-get remove --purge --auto-remove -y gnupg1 && rm -rf /var/lib/apt/lists/* \ && dpkgArch="$(dpkg --print-architecture)" \ && nginxPackages=" \ nginx=${NGINX_VERSION}-${PKG_RELEASE} \ - nginx-module-xslt=${NGINX_VERSION}-${PKG_RELEASE} \ - nginx-module-geoip=${NGINX_VERSION}-${PKG_RELEASE} \ - nginx-module-image-filter=${NGINX_VERSION}-${PKG_RELEASE} \ - nginx-module-njs=${NGINX_VERSION}+${NJS_VERSION}-${PKG_RELEASE} \ + nginx-module-xslt=${NGINX_VERSION}-${DYNPKG_RELEASE} \ + nginx-module-geoip=${NGINX_VERSION}-${DYNPKG_RELEASE} \ + nginx-module-image-filter=${NGINX_VERSION}-${DYNPKG_RELEASE} \ + nginx-module-njs=${NGINX_VERSION}+${NJS_VERSION}-${NJS_RELEASE} \ " \ && case "$dpkgArch" in \ amd64|arm64) \ # arches officialy built by upstream - echo "deb https://nginx.org/packages/debian/ bullseye nginx" >> /etc/apt/sources.list.d/nginx.list \ + echo "deb [signed-by=$NGINX_GPGKEY_PATH] https://nginx.org/packages/debian/ bookworm nginx" >> /etc/apt/sources.list.d/nginx.list \ && apt-get update \ ;; \ *) \ # we're on an architecture upstream doesn't officially build for -# let's build binaries from the published source packages - echo "deb-src https://nginx.org/packages/debian/ bullseye nginx" >> /etc/apt/sources.list.d/nginx.list \ - \ +# let's build binaries from the published packaging sources # new directory for storing sources and .deb files - && tempDir="$(mktemp -d)" \ + tempDir="$(mktemp -d)" \ && chmod 777 "$tempDir" \ # (777 to ensure APT's "_apt" user can access it too) \ # save list of currently-installed packages so build dependencies can be cleanly removed later && savedAptMark="$(apt-mark showmanual)" \ \ -# build .deb files from upstream's source packages (which are verified by apt-get) +# build .deb files from upstream's packaging sources && apt-get update \ - && apt-get build-dep -y $nginxPackages \ + && apt-get install --no-install-recommends --no-install-suggests -y \ + curl \ + devscripts \ + equivs \ + git \ + libxml2-utils \ + lsb-release \ + xsltproc \ && ( \ cd "$tempDir" \ - && DEB_BUILD_OPTIONS="nocheck parallel=$(nproc)" \ - apt-get source --compile $nginxPackages \ + && REVISION="${NGINX_VERSION}-${PKG_RELEASE}" \ + && REVISION=${REVISION%~*} \ + && curl -f -L -O https://github.com/nginx/pkg-oss/archive/${REVISION}.tar.gz \ + && PKGOSSCHECKSUM="517bc18954ccf4efddd51986584ca1f37966833ad342a297e1fe58fd0faf14c5a4dabcb23519dca433878a2927a95d6bea05a6749ee2fa67a33bf24cdc41b1e4 *${REVISION}.tar.gz" \ + && if [ "$(openssl sha512 -r ${REVISION}.tar.gz)" = "$PKGOSSCHECKSUM" ]; then \ + echo "pkg-oss tarball checksum verification succeeded!"; \ + else \ + echo "pkg-oss tarball checksum verification failed!"; \ + exit 1; \ + fi \ + && tar xzvf ${REVISION}.tar.gz \ + && cd pkg-oss-${REVISION} \ + && cd debian \ + && for target in base module-geoip module-image-filter module-njs module-xslt; do \ + make rules-$target; \ + mk-build-deps --install --tool="apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends --yes" \ + debuild-$target/nginx-$NGINX_VERSION/debian/control; \ + done \ + && make base module-geoip module-image-filter module-njs module-xslt \ ) \ # we don't remove APT lists here because they get re-downloaded and removed later \ @@ -103,6 +133,7 @@ RUN set -x \ COPY docker-entrypoint.sh / COPY 10-listen-on-ipv6-by-default.sh /docker-entrypoint.d +COPY 15-local-resolvers.envsh /docker-entrypoint.d COPY 20-envsubst-on-templates.sh /docker-entrypoint.d COPY 30-tune-worker-processes.sh /docker-entrypoint.d ENTRYPOINT ["/docker-entrypoint.sh"] diff --git a/stable/debian/docker-entrypoint.sh b/stable/debian/docker-entrypoint.sh index 72d5cd94e..8ea04f217 100755 --- a/stable/debian/docker-entrypoint.sh +++ b/stable/debian/docker-entrypoint.sh @@ -3,35 +3,44 @@ set -e -if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then - exec 3>&1 -else - exec 3>/dev/null -fi +entrypoint_log() { + if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then + echo "$@" + fi +} -if [ "$1" = "nginx" -o "$1" = "nginx-debug" ]; then +if [ "$1" = "nginx" ] || [ "$1" = "nginx-debug" ]; then if /usr/bin/find "/docker-entrypoint.d/" -mindepth 1 -maxdepth 1 -type f -print -quit 2>/dev/null | read v; then - echo >&3 "$0: /docker-entrypoint.d/ is not empty, will attempt to perform configuration" + entrypoint_log "$0: /docker-entrypoint.d/ is not empty, will attempt to perform configuration" - echo >&3 "$0: Looking for shell scripts in /docker-entrypoint.d/" + entrypoint_log "$0: Looking for shell scripts in /docker-entrypoint.d/" find "/docker-entrypoint.d/" -follow -type f -print | sort -V | while read -r f; do case "$f" in + *.envsh) + if [ -x "$f" ]; then + entrypoint_log "$0: Sourcing $f"; + . "$f" + else + # warn on shell scripts without exec bit + entrypoint_log "$0: Ignoring $f, not executable"; + fi + ;; *.sh) if [ -x "$f" ]; then - echo >&3 "$0: Launching $f"; + entrypoint_log "$0: Launching $f"; "$f" else # warn on shell scripts without exec bit - echo >&3 "$0: Ignoring $f, not executable"; + entrypoint_log "$0: Ignoring $f, not executable"; fi ;; - *) echo >&3 "$0: Ignoring $f";; + *) entrypoint_log "$0: Ignoring $f";; esac done - echo >&3 "$0: Configuration complete; ready for start up" + entrypoint_log "$0: Configuration complete; ready for start up" else - echo >&3 "$0: No files found in /docker-entrypoint.d/, skipping configuration" + entrypoint_log "$0: No files found in /docker-entrypoint.d/, skipping configuration" fi fi diff --git a/sync-awsecr.sh b/sync-awsecr.sh index 3e10a9ba1..599a33a12 100755 --- a/sync-awsecr.sh +++ b/sync-awsecr.sh @@ -6,8 +6,8 @@ registry="public.ecr.aws/z9d2n7e1" declare -A aliases aliases=( - [mainline]='1 1.23 latest' - [stable]='1.22' + [mainline]='1 1.29 latest' + [stable]='1.28' ) architectures=( amd64 arm64v8 ) @@ -55,7 +55,7 @@ for version in "${versions[@]}"; do commit="$(dirCommit "$version/$base")" fullVersion="$(git show "$commit":"$version/$base/Dockerfile" | awk '$1 == "ENV" && $2 == "NGINX_VERSION" { print $3; exit }')" pulllist+=( "$image:$fullVersion" ) - for variant in perl alpine alpine-perl; do + for variant in perl alpine alpine-perl alpine-slim; do pulllist+=( "$image:$fullVersion-$variant" ) done done @@ -71,12 +71,17 @@ for version in "${versions[@]}"; do fi versionAliases+=( ${aliases[$version]:-} ) - for tag in ${versionAliases[@]:1}; do + debianVersion="$(git show "$commit":"$version/$base/Dockerfile" | awk -F"[-:]" '$1 == "FROM debian" { print $2; exit }')" + debianAliases=( ${versionAliases[@]/%/-$debianVersion} ) + debianAliases=( "${debianAliases[@]//latest-/}" ) + + for tag in ${versionAliases[@]:1} ${debianAliases[@]:1}; do taglist["$image:$tag"]="$image:$fullVersion" done for variant in debian-perl; do variantAliases=( "${versionAliases[@]/%/-perl}" ) + variantAliases+=( "${versionAliases[@]/%/-${variant/debian/$debianVersion}}" ) variantAliases=( "${variantAliases[@]//latest-/}" ) for tag in ${variantAliases[@]}; do @@ -86,10 +91,14 @@ for version in "${versions[@]}"; do done done - for variant in alpine alpine-perl; do + commit="$(dirCommit "$version/alpine-slim")" + alpineVersion="$(git show "$commit":"$version/alpine-slim/Dockerfile" | awk -F: '$1 == "FROM alpine" { print $2; exit }')" + + for variant in alpine alpine-perl alpine-slim; do commit="$(dirCommit "$version/$variant")" variantAliases=( "${versionAliases[@]/%/-$variant}" ) + variantAliases+=( "${versionAliases[@]/%/-${variant/alpine/alpine$alpineVersion}}" ) variantAliases=( "${variantAliases[@]//latest-/}" ) for tag in ${variantAliases[@]}; do @@ -108,8 +117,16 @@ echo "export DOCKER_CLI_EXPERIMENTAL=enabled" echo echo "# pulling stuff" for arch in ${architectures[@]}; do + case $arch in + arm64v8) + parch="aarch64" + ;; + *) + parch=$arch + ;; + esac for tag in ${pulllist[@]}; do - echo "docker pull $arch/$tag"; + echo "docker pull --platform linux/$parch $arch/$tag"; done done diff --git a/update.sh b/update.sh index 6f0bb0002..50f9d2a11 100755 --- a/update.sh +++ b/update.sh @@ -12,48 +12,68 @@ declare branches=( # Current nginx versions # Remember to update pkgosschecksum when changing this. declare -A nginx=( - [mainline]='1.23.0' - [stable]='1.22.0' + [mainline]='1.29.3' + [stable]='1.28.0' ) # Current njs versions declare -A njs=( - [mainline]='0.7.5' - [stable]='0.7.5' + [mainline]='0.9.4' + [stable]='0.8.10' ) -# Current package patchlevel version +# Current njs patchlevel version +# Remember to update pkgosschecksum when changing this. +declare -A njspkg=( + [mainline]='1' + [stable]='1' +) + +# Current otel versions +declare -A otel=( + [mainline]='0.1.2' + [stable]='0.1.2' +) + +# Current nginx package patchlevel version # Remember to update pkgosschecksum when changing this. declare -A pkg=( [mainline]=1 [stable]=1 ) +# Current built-in dynamic modules package patchlevel version +# Remember to update pkgosschecksum when changing this +declare -A dynpkg=( + [mainline]=1 + [stable]=1 +) + declare -A debian=( - [mainline]='bullseye' - [stable]='bullseye' + [mainline]='trixie' + [stable]='bookworm' ) declare -A alpine=( - [mainline]='3.16' - [stable]='3.16' + [mainline]='3.22' + [stable]='3.21' ) # When we bump njs version in a stable release we don't move the tag in the -# mercurial repo. This setting allows us to specify a revision to check out -# when building alpine packages on architectures not supported by nginx.org +# pkg-oss repo. This setting allows us to specify a revision to check out +# when building packages on architectures not supported by nginx.org # Remember to update pkgosschecksum when changing this. declare -A rev=( [mainline]='${NGINX_VERSION}-${PKG_RELEASE}' - [stable]='714' + [stable]='${NGINX_VERSION}-${PKG_RELEASE}' ) # Holds SHA512 checksum for the pkg-oss tarball produced by source code # revision/tag in the previous block -# Used in alpine builds for architectures not packaged by nginx.org +# Used in builds for architectures not packaged by nginx.org declare -A pkgosschecksum=( - [mainline]='678b1e9ab34777f1a1a1a8717aff0dfa08cc187cf2cf140c084d23205f3ba3af97805e72ebbed49dd7bfcb23bbeca982b150fff5c2a6c96f161ed9085101f1a4' - [stable]='f457d5988c1f2663e04c5cdad71874c25e94754277dd9da5d73c1d37c32bdaf288b3b20d8b5d070ffb33aab363eaf4a7abbcf95fcfd72b0729a1c1908c37e30e' + [mainline]='249858446828ace0c81ea3e057135aa368f3dab83430cf867bb9fc32598948f29c4bd50908491da704536af1106aa87553f6a76cc126c6833dc9b14dd00564b8' + [stable]='517bc18954ccf4efddd51986584ca1f37966833ad342a297e1fe58fd0faf14c5a4dabcb23519dca433878a2927a95d6bea05a6749ee2fa67a33bf24cdc41b1e4' ) get_packages() { @@ -61,6 +81,8 @@ get_packages() { shift local branch="$1" shift + local bn="" + local otel= local perl= local r= local sep= @@ -79,20 +101,42 @@ get_packages() { *-perl) perl="nginx-module-perl" ;; + *-otel) + otel="nginx-module-otel" + bn="\n" + ;; esac echo -n ' \\\n' - for p in nginx nginx-module-xslt nginx-module-geoip nginx-module-image-filter $perl; do - echo -n ' '"$p"'=${NGINX_VERSION}-'"$r"'${PKG_RELEASE} \\\n' - done - for p in nginx-module-njs; do - echo -n ' '"$p"'=${NGINX_VERSION}'"$sep"'${NJS_VERSION}-'"$r"'${PKG_RELEASE} \\' - done + case "$distro" in + *-slim) + for p in nginx; do + echo -n ' '"$p"'=${NGINX_VERSION}-'"$r"'${PKG_RELEASE} \\' + done + ;; + *) + for p in nginx; do + echo -n ' '"$p"'=${NGINX_VERSION}-'"$r"'${PKG_RELEASE} \\\n' + done + for p in nginx-module-xslt nginx-module-geoip nginx-module-image-filter $perl; do + echo -n ' '"$p"'=${NGINX_VERSION}-'"$r"'${DYNPKG_RELEASE} \\\n' + done + for p in nginx-module-njs; do + echo -n ' '"$p"'=${NGINX_VERSION}'"$sep"'${NJS_VERSION}-'"$r"'${NJS_RELEASE} \\'"$bn" + done + for p in $otel; do + echo -n ' '"$p"'=${NGINX_VERSION}'"$sep"'${OTEL_VERSION}-'"$r"'${PKG_RELEASE} \\' + done + ;; + esac } get_packagerepo() { - local distro="${1%-perl}" + local distro="$1" shift + distro="${distro%-perl}" + distro="${distro%-otel}" + distro="${distro%-slim}" local branch="$1" shift @@ -102,15 +146,52 @@ get_packagerepo() { } get_packagever() { - local distro="${1%-perl}" + local distro="$1" shift + distro="${distro%-perl}" + distro="${distro%-otel}" + distro="${distro%-slim}" local branch="$1" shift + local package="$1" + shift local suffix= [ "${distro}" = "debian" ] && suffix="~${debianver}" - echo ${pkg[$branch]}${suffix} + case "${package}" in + "njs") + echo ${njspkg[$branch]}${suffix} + ;; + "dyn") + echo ${dynpkg[$branch]}${suffix} + ;; + *) + echo ${pkg[$branch]}${suffix} + ;; + esac +} + +get_buildtarget() { + local distro="$1" + shift + case "$distro" in + alpine-slim) + echo base + ;; + alpine) + echo module-geoip module-image-filter module-njs module-xslt + ;; + debian) + echo base module-geoip module-image-filter module-njs module-xslt + ;; + *-perl) + echo module-perl + ;; + *-otel) + echo module-otel + ;; + esac } generated_warning() { @@ -125,15 +206,15 @@ __EOF__ for branch in "${branches[@]}"; do for variant in \ - alpine{,-perl} \ - debian{,-perl}; do - echo "$branch: $variant" + alpine{,-perl,-otel,-slim} \ + debian{,-perl,-otel}; do + echo "$branch: $variant dockerfiles" dir="$branch/$variant" variant="$(basename "$variant")" [ -d "$dir" ] || continue - template="Dockerfile-${variant%-perl}.template" + template="Dockerfile-${variant}.template" { generated_warning cat "$template" @@ -143,26 +224,41 @@ for branch in "${branches[@]}"; do alpinever="${alpine[$branch]}" nginxver="${nginx[$branch]}" njsver="${njs[${branch}]}" + otelver="${otel[${branch}]}" revver="${rev[${branch}]}" pkgosschecksumver="${pkgosschecksum[${branch}]}" packagerepo=$(get_packagerepo "$variant" "$branch") packages=$(get_packages "$variant" "$branch") - packagever=$(get_packagever "$variant" "$branch") + packagever=$(get_packagever "$variant" "$branch" "any") + njspkgver=$(get_packagever "$variant" "$branch" "njs") + dynpkgver=$(get_packagever "$variant" "$branch" "dyn") + buildtarget=$(get_buildtarget "$variant") sed -i.bak \ -e 's,%%ALPINE_VERSION%%,'"$alpinever"',' \ -e 's,%%DEBIAN_VERSION%%,'"$debianver"',' \ + -e 's,%%DYNPKG_RELEASE%%,'"$dynpkgver"',' \ -e 's,%%NGINX_VERSION%%,'"$nginxver"',' \ -e 's,%%NJS_VERSION%%,'"$njsver"',' \ + -e 's,%%NJS_RELEASE%%,'"$njspkgver"',' \ + -e 's,%%OTEL_VERSION%%,'"$otelver"',' \ -e 's,%%PKG_RELEASE%%,'"$packagever"',' \ -e 's,%%PACKAGES%%,'"$packages"',' \ -e 's,%%PACKAGEREPO%%,'"$packagerepo"',' \ -e 's,%%REVISION%%,'"$revver"',' \ -e 's,%%PKGOSSCHECKSUM%%,'"$pkgosschecksumver"',' \ + -e 's,%%BUILDTARGET%%,'"$buildtarget"',' \ "$dir/Dockerfile" - cp -a entrypoint/*.sh "$dir/" + done + for variant in \ + alpine-slim \ + debian; do \ + echo "$branch: $variant entrypoint scripts" + dir="$branch/$variant" + cp -a entrypoint/*.sh "$dir/" + cp -a entrypoint/*.envsh "$dir/" done done