9 Commits

Author SHA1 Message Date
github-actions[bot]
a88b52f302 update README.md 2025-08-03 01:36:00 +00:00
ElevenNotes
8f4f43209d refactor: add payload and distroless defaults 2025-08-03 03:18:01 +02:00
ElevenNotes
3bfd480cd6 docs: verify payload info 2025-08-03 03:17:39 +02:00
ElevenNotes
24b979658c docs: add introduction 2025-08-03 03:17:25 +02:00
ElevenNotes
83245bcf5f chore: upgrade to latest workflow 2025-08-03 03:17:10 +02:00
ElevenNotes
9aa7f4d4e4 docs: UVP style 2025-07-31 11:35:16 +02:00
ElevenNotes
fbc33ffd62 cut: armv7 2025-07-31 11:35:03 +02:00
ElevenNotes
aabfbaa41a chore: upgrade to latest workflows 2025-07-31 11:34:21 +02:00
github-actions[bot]
f87bb65981 github-actions[bot]: update README.md 2025-06-04 19:56:23 +00:00
8 changed files with 576 additions and 169 deletions

115
.github/workflows/cron.update.yml vendored Normal file
View File

@@ -0,0 +1,115 @@
name: cron-update
on:
workflow_dispatch:
schedule:
- cron: "0 5 * * *"
jobs:
cron-update:
runs-on: ubuntu-latest
permissions:
actions: read
contents: write
steps:
- name: init / checkout
uses: actions/checkout@85e6279cec87321a52edac9c87bce653a07cf6c2
with:
ref: 'master'
fetch-depth: 0
- name: cron-update / get latest version
run: |
echo "LATEST_VERSION=$(curl -sSL https://nginx.org/en/download.html | grep -oE '<a href="/download/nginx-[0-9]+.[0-9]+.[0-9]+.tar.gz">nginx-[0-9]+.[0-9]+.[0-9]+</a>' | head -n 2 | tail -n 1 | grep -oE 'nginx-[0-9]+.[0-9]+.[0-9]+' | head -n 2 | tail -n 1 | sed 's/nginx-//')" >> "${GITHUB_ENV}"
echo "LATEST_TAG=$(git describe --abbrev=0 --tags `git rev-list --tags --max-count=1` | sed 's/v//')" >> "${GITHUB_ENV}"
- name: cron-update / setup node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
with:
node-version: '20'
- run: npm i semver
- name: cron-update / compare latest with current version
uses: actions/github-script@62c3794a3eb6788d9a2a72b219504732c0c9a298
with:
script: |
const { existsSync, readFileSync, writeFileSync } = require('node:fs');
const { resolve } = require('node:path');
const { inspect } = require('node:util');
const semver = require('semver')
const repository = {dot:{}};
try{
const path = resolve('.json');
if(existsSync(path)){
try{
repository.dot = JSON.parse(readFileSync(path).toString());
}catch(e){
throw new Error('could not parse .json');
}
}else{
throw new Error('.json does not exist');
}
}catch(e){
core.setFailed(e);
}
const latest = semver.valid(semver.coerce('${{ env.LATEST_VERSION }}'));
const current = semver.valid(semver.coerce(repository.dot.semver.version));
const tag = semver.valid(semver.coerce('${{ env.LATEST_TAG }}'));
if(latest && latest !== current){
core.info(`new ${semver.diff(current, latest)} release found (${latest})!`)
repository.dot.semver.version = latest;
if(tag){
core.exportVariable('WORKFLOW_NEW_TAG', semver.inc(tag, semver.diff(current, latest)));
}
if(repository.dot.semver?.latest){
repository.dot.semver.latest = repository.dot.semver.version;
}
if(repository.dot?.readme?.comparison?.image){
repository.dot.readme.comparison.image = repository.dot.readme.comparison.image.replace(current, repository.dot.semver.version);
}
try{
writeFileSync(resolve('.json'), JSON.stringify(repository.dot, null, 2));
core.exportVariable('WORKFLOW_AUTO_UPDATE', true);
}catch(e){
core.setFailed(e);
}
}else{
core.info('no new release found');
}
core.info(inspect(repository.dot, {showHidden:false, depth:null, colors:true}));
- name: cron-update / checkout
id: checkout
if: env.WORKFLOW_AUTO_UPDATE == 'true'
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add .json
git commit -m "chore: auto upgrade to ${{ env.LATEST_VERSION }}"
git push origin HEAD:master
- name: cron-update / tag
if: env.WORKFLOW_AUTO_UPDATE == 'true' && steps.checkout.outcome == 'success'
run: |
SHA256=$(git rev-list --branches --max-count=1)
git tag -a v${{ env.WORKFLOW_NEW_TAG }} -m "v${{ env.WORKFLOW_NEW_TAG }}" ${SHA256}
git push --follow-tags
- name: cron-update / build docker image
if: env.WORKFLOW_AUTO_UPDATE == 'true' && steps.checkout.outcome == 'success'
uses: the-actions-org/workflow-dispatch@3133c5d135c7dbe4be4f9793872b6ef331b53bc7
with:
workflow: docker.yml
wait-for-completion: false
token: "${{ secrets.REPOSITORY_TOKEN }}"
inputs: '{ "release":"true", "readme":"true" }'
ref: "v${{ env.WORKFLOW_NEW_TAG }}"

70
.github/workflows/cve.yml vendored Normal file
View File

@@ -0,0 +1,70 @@
name: cve
on:
workflow_dispatch:
schedule:
- cron: "30 15 */2 * *"
jobs:
cve:
runs-on: ubuntu-latest
steps:
- name: init / checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
ref: ${{ github.ref_name }}
fetch-depth: 0
- name: init / setup environment
uses: actions/github-script@62c3794a3eb6788d9a2a72b219504732c0c9a298
with:
script: |
const { existsSync, readFileSync } = require('node:fs');
const { resolve } = require('node:path');
const { inspect } = require('node:util');
const { Buffer } = require('node:buffer');
const inputs = `${{ toJSON(github.event.inputs) }}`;
const opt = {input:{}, dot:{}};
try{
if(inputs.length > 0){
opt.input = JSON.parse(inputs);
if(opt.input?.etc){
opt.input.etc = JSON.parse(Buffer.from(opt.input.etc, 'base64').toString('ascii'));
}
}
}catch(e){
core.warning('could not parse github.event.inputs');
}
try{
const path = resolve('.json');
if(existsSync(path)){
try{
opt.dot = JSON.parse(readFileSync(path).toString());
}catch(e){
throw new Error('could not parse .json');
}
}else{
throw new Error('.json does not exist');
}
}catch(e){
core.setFailed(e);
}
core.info(inspect(opt, {showHidden:false, depth:null, colors:true}));
core.exportVariable('WORKFLOW_IMAGE', `${opt.dot.image}:${(opt.dot?.semver?.version === undefined) ? 'rolling' : opt.dot.semver.version}`);
core.exportVariable('WORKFLOW_GRYPE_SEVERITY_CUTOFF', (opt.dot?.grype?.severity || 'high'));
- name: grype / scan
id: grype
uses: anchore/scan-action@dc6246fcaf83ae86fcc6010b9824c30d7320729e
with:
image: ${{ env.WORKFLOW_IMAGE }}
fail-build: true
severity-cutoff: ${{ env.WORKFLOW_GRYPE_SEVERITY_CUTOFF }}
output-format: 'sarif'
by-cve: true
cache-db: true

View File

@@ -16,6 +16,7 @@ on:
required: false
default: 'ubuntu-22.04'
build:
description: 'set WORKFLOW_BUILD'
required: false
@@ -100,7 +101,7 @@ jobs:
const docker = {
image:{
name:opt.dot.image,
arch:(opt.dot.arch || 'linux/amd64,linux/arm64'),
arch:(opt.input?.etc?.arch || opt.dot?.arch || 'linux/amd64,linux/arm64'),
prefix:((opt.input?.etc?.semverprefix) ? `${opt.input?.etc?.semverprefix}-` : ''),
suffix:((opt.input?.etc?.semversuffix) ? `-${opt.input?.etc?.semversuffix}` : ''),
description:(opt.dot?.readme?.description || ''),
@@ -227,7 +228,7 @@ jobs:
with:
driver-opts: network=host
- name: docker / build & push & tag grype
- name: docker / build image locally
if: env.WORKFLOW_BUILD == 'true'
id: docker-build
uses: docker/build-push-action@67a2d409c0a876cbe6b11854e3e25193efe4e62d
@@ -256,7 +257,7 @@ jobs:
cache-db: true
- name: grype / fail
if: env.WORKFLOW_BUILD == 'true' && (failure() || steps.grype.outcome == 'failure')
if: env.WORKFLOW_BUILD == 'true' && (failure() || steps.grype.outcome == 'failure') && steps.docker-build.outcome == 'success'
uses: anchore/scan-action@dc6246fcaf83ae86fcc6010b9824c30d7320729e
with:
image: ${{ env.DOCKER_CACHE_GRYPE }}
@@ -266,7 +267,7 @@ jobs:
by-cve: true
cache-db: true
- name: docker / build & push
- name: docker / build image from cache and push to registries
if: env.WORKFLOW_BUILD == 'true'
uses: docker/build-push-action@67a2d409c0a876cbe6b11854e3e25193efe4e62d
with:
@@ -286,21 +287,8 @@ jobs:
# RELEASE
- name: github / release / log
continue-on-error: true
id: git-log
run: |
LOCAL_LAST_TAG=$(git describe --abbrev=0 --tags `git rev-list --tags --skip=1 --max-count=1`)
echo "using last tag: ${LOCAL_LAST_TAG}"
LOCAL_COMMITS=$(git log ${LOCAL_LAST_TAG}..HEAD --oneline)
EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64)
echo "commits<<${EOF}" >> ${GITHUB_OUTPUT}
echo "${LOCAL_COMMITS}" >> ${GITHUB_OUTPUT}
echo "${EOF}" >> ${GITHUB_OUTPUT}
- name: github / release / markdown
if: env.WORKFLOW_CREATE_RELEASE == 'true' && steps.git-log.outcome == 'success'
if: env.WORKFLOW_CREATE_RELEASE == 'true'
id: git-release
uses: 11notes/action-docker-release@v1
# WHY IS THIS ACTION NOT SHA256 PINNED? SECURITY MUCH?!?!?!
@@ -309,8 +297,6 @@ jobs:
# in the repo. This code is not modified and can't be modified by this action.
# It does create the markdown for the release, which could be abused, but to what
# extend? Adding a link to a malicious repo?
with:
git_log: ${{ steps.git-log.outputs.commits }}
- name: github / release / create
if: env.WORKFLOW_CREATE_RELEASE == 'true' && steps.git-release.outcome == 'success'
@@ -412,10 +398,13 @@ jobs:
if [ -f compose.yaml ]; then
git add compose.yaml
fi
if [ -f compose.yml ]; then
git add compose.yml
fi
if [ -f LICENSE ]; then
git add LICENSE
fi
git commit -m "github-actions[bot]: update README.md"
git commit -m "update README.md"
git push origin HEAD:master

6
.json
View File

@@ -2,7 +2,6 @@
"image":"11notes/nginx",
"name":"nginx",
"root":"/nginx",
"arch":"linux/amd64,linux/arm64,linux/arm/v7",
"semver":{
"version":"1.28.0",
@@ -10,7 +9,8 @@
},
"readme":{
"description":"Nginx, slim and distroless to be used behind a reverse proxy or as full version",
"description":"Nginx, slim and distroless to be used behind a reverse proxy or as full version as a proxy",
"introduction": "nginx (engine x) is an HTTP web server, reverse proxy, content cache, load balancer, TCP/UDP proxy server, and mail proxy server.",
"built":{
"nginx":"https://nginx.org"
},
@@ -21,7 +21,7 @@
]
},
"comparison":{
"image":"nginx:1.28.0-alpine-slim"
"image":"nginx:1.28.0"
}
}
}

View File

@@ -1,47 +1,39 @@
![banner](https://github.com/11notes/defaults/blob/main/static/img/banner.png?raw=true)
# NGINX
[<img src="https://img.shields.io/badge/github-source-blue?logo=github&color=040308">](https://github.com/11notes/docker-NGINX)![5px](https://github.com/11notes/defaults/blob/main/static/img/transparent5x2px.png?raw=true)![size](https://img.shields.io/docker/image-size/11notes/nginx/1.28.0?color=0eb305)![5px](https://github.com/11notes/defaults/blob/main/static/img/transparent5x2px.png?raw=true)![version](https://img.shields.io/docker/v/11notes/nginx/1.28.0?color=eb7a09)![5px](https://github.com/11notes/defaults/blob/main/static/img/transparent5x2px.png?raw=true)![pulls](https://img.shields.io/docker/pulls/11notes/nginx?color=2b75d6)![5px](https://github.com/11notes/defaults/blob/main/static/img/transparent5x2px.png?raw=true)[<img src="https://img.shields.io/github/issues/11notes/docker-NGINX?color=7842f5">](https://github.com/11notes/docker-NGINX/issues)![5px](https://github.com/11notes/defaults/blob/main/static/img/transparent5x2px.png?raw=true)![swiss_made](https://img.shields.io/badge/Swiss_Made-FFFFFF?labelColor=FF0000&logo=data:image/svg%2bxml;base64,PHN2ZyB2ZXJzaW9uPSIxIiB3aWR0aD0iNTEyIiBoZWlnaHQ9IjUxMiIgdmlld0JveD0iMCAwIDMyIDMyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Im0wIDBoMzJ2MzJoLTMyeiIgZmlsbD0iI2YwMCIvPjxwYXRoIGQ9Im0xMyA2aDZ2N2g3djZoLTd2N2gtNnYtN2gtN3YtNmg3eiIgZmlsbD0iI2ZmZiIvPjwvc3ZnPg==)
![size](https://img.shields.io/docker/image-size/11notes/nginx/1.28.0?color=0eb305)![5px](https://github.com/11notes/defaults/blob/main/static/img/transparent5x2px.png?raw=true)![version](https://img.shields.io/docker/v/11notes/nginx/1.28.0?color=eb7a09)![5px](https://github.com/11notes/defaults/blob/main/static/img/transparent5x2px.png?raw=true)![pulls](https://img.shields.io/docker/pulls/11notes/nginx?color=2b75d6)![5px](https://github.com/11notes/defaults/blob/main/static/img/transparent5x2px.png?raw=true)[<img src="https://img.shields.io/github/issues/11notes/docker-NGINX?color=7842f5">](https://github.com/11notes/docker-NGINX/issues)![5px](https://github.com/11notes/defaults/blob/main/static/img/transparent5x2px.png?raw=true)![swiss_made](https://img.shields.io/badge/Swiss_Made-FFFFFF?labelColor=FF0000&logo=data:image/svg%2bxml;base64,PHN2ZyB2ZXJzaW9uPSIxIiB3aWR0aD0iNTEyIiBoZWlnaHQ9IjUxMiIgdmlld0JveD0iMCAwIDMyIDMyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogIDxyZWN0IHdpZHRoPSIzMiIgaGVpZ2h0PSIzMiIgZmlsbD0idHJhbnNwYXJlbnQiLz4KICA8cGF0aCBkPSJtMTMgNmg2djdoN3Y2aC03djdoLTZ2LTdoLTd2LTZoN3oiIGZpbGw9IiNmZmYiLz4KPC9zdmc+)
Nginx, slim and distroless to be used behind a reverse proxy or as full version
Nginx, slim and distroless to be used behind a reverse proxy or as full version as a proxy
# MAIN TAGS 🏷️
These are the main tags for the image. There is also a tag for each commit and its shorthand sha256 value.
# INTRODUCTION 📢
* [1.28.0](https://hub.docker.com/r/11notes/nginx/tags?name=1.28.0)
* [stable](https://hub.docker.com/r/11notes/nginx/tags?name=stable)
* [latest](https://hub.docker.com/r/11notes/nginx/tags?name=latest)
# REPOSITORIES ☁️
```
docker pull 11notes/nginx:1.28.0
docker pull ghcr.io/11notes/nginx:1.28.0
docker pull quay.io/11notes/nginx:1.28.0
```
nginx (engine x) is an HTTP web server, reverse proxy, content cache, load balancer, TCP/UDP proxy server, and mail proxy server.
# SYNOPSIS 📖
**What can I do with this?** This image will serve as a base for nginx related images that need a high-performance webserver. The default tag of this image is stripped for most functions that can be used by a reverse proxy in front of nginx, it adds however important webserver functions like brotli compression. The default tag is not meant to run as a reverse proxy, use the full image for that. The default tag does not support HTTPS for instance!
**What can I do with this?** This image will serve as a base for nginx related images that need a high-performance webserver. The default tag of this image is stripped for most functions that can be used by a reverse proxy in front of nginx, it adds however important webserver functions like brotli compression. The default tag is not meant to run as a reverse proxy, use the full image for that. **The default tag does not support HTTPS for instance!**
# UNIQUE VALUE PROPOSITION 💶
**Why should I run this image and not the other image(s) that already exist?** Good question! All the other images on the market that do exactly the same dont do or offer these options:
**Why should I run this image and not the other image(s) that already exist?** Good question! Because ...
> [!IMPORTANT]
>* This image runs as 1000:1000 by default, most other images run everything as root
>* This image has no shell since it is 100% distroless, most other images run on a distro like Debian or Alpine with full shell access (security)
>* This image does not ship with any critical or high rated CVE and is automatically maintained via CI/CD, most other images mostly have no CVE scanning or code quality tools in place
>* This image is created via a secure, pinned CI/CD process and immune to upstream attacks, most other images have upstream dependencies that can be exploited
>* This image contains a proper health check that verifies the app is actually working, most other images have either no health check or only check if a port is open or ping works
>* This image works as read-only, most other images need to write files to the image filesystem
>* This image is a lot smaller than most other images
>* ... this image runs [rootless](https://github.com/11notes/RTFM/blob/main/linux/container/image/rootless.md) as 1000:1000
>* ... this image has no shell since it is [distroless](https://github.com/11notes/RTFM/blob/main/linux/container/image/distroless.md)
>* ... this image is auto updated to the latest version via CI/CD
>* ... this image has a health check
>* ... this image runs read-only
>* ... this image is automatically scanned for CVEs before and after publishing
>* ... this image is created via a secure and pinned CI/CD process
>* ... this image verifies external payloads if possible
>* ... this image is very small
If you value security, simplicity and the ability to interact with the maintainer and developer of an image. Using my images is a great start in that direction.
If you value security, simplicity and optimizations to the extreme, then this image might be for you.
# COMPARISON 🏁
Below you find a comparison between this image and the most used or original one.
| ![128px](https://github.com/11notes/defaults/blob/main/static/img/transparent128x1px.png?raw=true)**image** | 11notes/nginx:1.28.0 | nginx:1.28.0-alpine-slim |
| **image** | 11notes/nginx:1.28.0 | nginx:1.28.0 |
| ---: | :---: | :---: |
| **image size on disk** | 4.4MB | 11.9MB |
| **image size on disk** | 3.69MB | 192MB |
| **process UID/GID** | 1000/1000 | 0/0 |
| **distroless?** | ✅ | ❌ |
| **rootless?** | ✅ | ❌ |
@@ -175,6 +167,24 @@ networks:
| `TZ` | [Time Zone](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) | |
| `DEBUG` | Will activate debug option for container image and app (if available) | |
# MAIN TAGS 🏷️
These are the main tags for the image. There is also a tag for each commit and its shorthand sha256 value.
* [1.28.0](https://hub.docker.com/r/11notes/nginx/tags?name=1.28.0)
* [stable](https://hub.docker.com/r/11notes/nginx/tags?name=stable)
### There is no latest tag, what am I supposed to do about updates?
It is of my opinion that the ```:latest``` tag is dangerous. Many times, Ive introduced **breaking** changes to my images. This would have messed up everything for some people. If you dont want to change the tag to the latest [semver](https://semver.org/), simply use the short versions of [semver](https://semver.org/). Instead of using ```:1.28.0``` you can use ```:1``` or ```:1.28```. Since on each new version these tags are updated to the latest version of the software, using them is identical to using ```:latest``` but at least fixed to a major or minor version.
If you still insist on having the bleeding edge release of this app, simply use the ```:rolling``` tag, but be warned! You will get the latest version of the app instantly, regardless of breaking changes or security issues or what so ever. You do this at your own risk!
# REGISTRIES ☁️
```
docker pull 11notes/nginx:1.28.0
docker pull ghcr.io/11notes/nginx:1.28.0
docker pull quay.io/11notes/nginx:1.28.0
```
# SOURCE 💾
* [11notes/nginx](https://github.com/11notes/docker-NGINX)
@@ -183,7 +193,7 @@ networks:
>This image is not based on another image but uses [scratch](https://hub.docker.com/_/scratch) as the starting layer.
>The image consists of the following distroless layers that were added:
>* [11notes/distroless](https://github.com/11notes/docker-distroless/blob/master/arch.dockerfile) - contains users, timezones and Root CA certificates
>* [11notes/distroless:curl](https://github.com/11notes/docker-distroless/blob/master/curl.dockerfile) - app to execute HTTP or UNIX requests
>* [11notes/distroless:curl](https://github.com/11notes/docker-distroless/blob/master/curl.dockerfile) - app to execute HTTP requests
# BUILT WITH 🧰
* [nginx](https://nginx.org)
@@ -196,4 +206,4 @@ networks:
# ElevenNotes™
This image is provided to you at your own risk. Always make backups before updating an image to a different version. Check the [releases](https://github.com/11notes/docker-nginx/releases) for breaking changes. If you have any problems with using this image simply raise an [issue](https://github.com/11notes/docker-nginx/issues), thanks. If you have a question or inputs please create a new [discussion](https://github.com/11notes/docker-nginx/discussions) instead of an issue. You can find all my other repositories on [github](https://github.com/11notes?tab=repositories).
*created 28.04.2025, 12:12:02 (CET)*
*created 03.08.2025, 03:35:59 (CET)*

View File

@@ -1,40 +1,70 @@
ARG APP_UID=1000
ARG APP_GID=1000
# ╔═════════════════════════════════════════════════════╗
# ║ SETUP ║
# ╚═════════════════════════════════════════════════════╝
# GLOBAL
ARG APP_UID=1000 \
APP_GID=1000 \
APP_VERSION=0 \
BUILD_NGINX_CONFIGURATION=light \
BUILD_DEPENDENCY_OPENSSL_VERSION=3.5.1 \
BUILD_DEPENDENCY_ZLIB_VERSION=1.3.1 \
BUILD_DEPENDENCY_ZLIB_SHA256=9a93b2b7dfdac77ceba5a558a580e74667dd6fede4585b91eefb60f03b72df23 \
BUILD_DEPENDENCY_PCRE2_VERSION=10.45 \
BUILD_DEPENDENCY_HEADERS_MORE_VERSION=0.39 \
BUILD_DEPENDENCY_QUICKJS_VERSION= \
BUILD_DEPENDENCY_NJS_VERSION=0.8.10 \
BUILD_NGINX_PREFIX=/etc/nginx
# :: Util
FROM 11notes/util AS util
ARG BUILD_ROOT=/nginx-${APP_VERSION} \
BUILD_DEPENDENCY_OPENSSL_ROOT=/openssl-${BUILD_DEPENDENCY_OPENSSL_VERSION} \
BUILD_DEPENDENCY_ZLIB_ROOT=/zlib-${BUILD_DEPENDENCY_ZLIB_VERSION} \
BUILD_DEPENDENCY_PCRE2_ROOT=/pcre2-${BUILD_DEPENDENCY_PCRE2_VERSION} \
BUILD_DEPENDENCY_HEADERS_MORE_ROOT=/headers-more-nginx-module-${BUILD_DEPENDENCY_HEADERS_MORE_VERSION} \
BUILD_DEPENDENCY_BROTLI_ROOT=/ngx_brotli \
BUILD_DEPENDENCY_NJS_ROOT=/njs-${BUILD_DEPENDENCY_NJS_VERSION} \
BUILD_DEPENDENCY_QUICKJS_ROOT=/quickjs${BUILD_DEPENDENCY_QUICKJS_VERSION} \
BUILD_BIN=${BUILD_ROOT}/objs/nginx
# :: Build / nginx
# :: FOREIGN IMAGES
FROM 11notes/distroless AS distroless
FROM 11notes/distroless:curl AS distroless-curl
FROM 11notes/util:bin AS util-bin
# ╔═════════════════════════════════════════════════════╗
# ║ BUILD ║
# ╚═════════════════════════════════════════════════════╝
# :: NGINX
FROM alpine AS build
ARG TARGETARCH
ARG TARGETPLATFORM
ARG TARGETVARIANT
ARG APP_ROOT
ARG APP_VERSION
ARG APP_NGINX_CONFIGURATION
ENV BUILD_ROOT=/nginx-${APP_VERSION}
ENV BUILD_BIN=${BUILD_ROOT}/objs/nginx
ENV NGINX_PREFIX=/etc/nginx
ENV BUILD_DEPENDENCY_OPENSSL_VERSION=3.5.0
ENV BUILD_DEPENDENCY_OPENSSL_ROOT=/openssl-${BUILD_DEPENDENCY_OPENSSL_VERSION}
ENV BUILD_DEPENDENCY_ZLIB_VERSION=1.3.1
ENV BUILD_DEPENDENCY_ZLIB_ROOT=/zlib-${BUILD_DEPENDENCY_ZLIB_VERSION}
ENV BUILD_DEPENDENCY_PCRE2_VERSION=10.45
ENV BUILD_DEPENDENCY_PCRE2_ROOT=/pcre2-${BUILD_DEPENDENCY_PCRE2_VERSION}
ENV BUILD_DEPENDENCY_HEADERS_MORE_VERSION=0.38
ENV BUILD_DEPENDENCY_HEADERS_MORE_ROOT=/headers-more-nginx-module-${BUILD_DEPENDENCY_HEADERS_MORE_VERSION}
ENV BUILD_DEPENDENCY_BROTLI_ROOT=/ngx_brotli
ENV BUILD_DEPENDENCY_NJS_VERSION=0.8.10
ENV BUILD_DEPENDENCY_NJS_ROOT=/njs-${BUILD_DEPENDENCY_NJS_VERSION}
ENV BUILD_DEPENDENCY_QUICKJS_VERSION=
ENV BUILD_DEPENDENCY_QUICKJS_ROOT=/quickjs${BUILD_DEPENDENCY_QUICKJS_VERSION}
COPY --from=util-bin / /
COPY ./key.txt /
USER root
COPY --from=util /usr/local/bin/ /usr/local/bin
ARG APP_UID \
APP_GID \
APP_VERSION \
APP_ROOT \
BUILD_DEPENDENCY_OPENSSL_VERSION \
BUILD_DEPENDENCY_ZLIB_VERSION \
BUILD_DEPENDENCY_ZLIB_SHA256 \
BUILD_DEPENDENCY_PCRE2_VERSION \
BUILD_DEPENDENCY_HEADERS_MORE_VERSION \
BUILD_DEPENDENCY_QUICKJS_VERSION \
BUILD_DEPENDENCY_NJS_VERSION \
BUILD_NGINX_PREFIX \
BUILD_NGINX_CONFIGURATION \
BUILD_ROOT \
BUILD_DEPENDENCY_OPENSSL_ROOT \
BUILD_DEPENDENCY_ZLIB_ROOT \
BUILD_DEPENDENCY_PCRE2_ROOT \
BUILD_DEPENDENCY_HEADERS_MORE_ROOT \
BUILD_DEPENDENCY_BROTLI_ROOT \
BUILD_DEPENDENCY_NJS_ROOT \
BUILD_DEPENDENCY_QUICKJS_ROOT \
BUILD_BIN
RUN set -ex; \
apk --update --no-cache add \
gpg \
gpg-agent \
cmake \
autoconf \
automake \
@@ -67,60 +97,63 @@ ARG APP_GID=1000
brotli-dev \
libgd \
tar \
xz \
upx;
pv \
jq \
xz;
RUN set -ex; \
gpg --import /key.txt;
RUN set -ex; \
cd /; \
curl -SL https://nginx.org/download/nginx-${APP_VERSION}.tar.gz | tar -zxC /; \
curl -SL https://zlib.net/fossils/zlib-${BUILD_DEPENDENCY_ZLIB_VERSION}.tar.gz | tar -zxC /; \
curl -SL https://github.com/PCRE2Project/pcre2/releases/download/pcre2-${BUILD_DEPENDENCY_PCRE2_VERSION}/pcre2-${BUILD_DEPENDENCY_PCRE2_VERSION}.tar.gz | tar -zxC /; \
curl -SL https://github.com/openresty/headers-more-nginx-module/archive/v${BUILD_DEPENDENCY_HEADERS_MORE_VERSION}.tar.gz | tar -zxC /;
eleven asset gpg-asc https://nginx.org/download/nginx-${APP_VERSION}.tar.gz https://nginx.org/download/nginx-${APP_VERSION}.tar.gz.asc; \
eleven asset sha256 https://zlib.net/zlib-${BUILD_DEPENDENCY_ZLIB_VERSION}.tar.gz ${BUILD_DEPENDENCY_ZLIB_SHA256}; \
eleven github asset PCRE2Project/pcre2 pcre2-${BUILD_DEPENDENCY_PCRE2_VERSION} pcre2-${BUILD_DEPENDENCY_PCRE2_VERSION}.tar.gz; \
eleven github asset openresty/headers-more-nginx-module v${BUILD_DEPENDENCY_HEADERS_MORE_VERSION} v${BUILD_DEPENDENCY_HEADERS_MORE_VERSION}.tar.gz;
RUN set -ex; \
#build OpenSSL
case "${APP_NGINX_CONFIGURATION}" in \
case "${BUILD_NGINX_CONFIGURATION}" in \
"full") \
cd /; \
curl -SL https://github.com/openssl/openssl/releases/download/openssl-${BUILD_DEPENDENCY_OPENSSL_VERSION}/openssl-${BUILD_DEPENDENCY_OPENSSL_VERSION}.tar.gz | tar -zxC /; \
eleven github asset openssl/openssl openssl-${BUILD_DEPENDENCY_OPENSSL_VERSION} openssl-${BUILD_DEPENDENCY_OPENSSL_VERSION}.tar.gz; \
;; \
esac;
RUN set -ex; \
# build brotli
cd /; \
git clone --recurse-submodules -j8 https://github.com/google/ngx_brotli; \
eleven git clone google/ngx_brotli.git; \
mkdir -p ${BUILD_DEPENDENCY_BROTLI_ROOT}/deps/brotli/out; \
cd ${BUILD_DEPENDENCY_BROTLI_ROOT}/deps/brotli/out; \
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DCMAKE_C_FLAGS="-Ofast -march=native -mtune=native -flto -funroll-loops -ffunction-sections -fdata-sections -Wl,--gc-sections" -DCMAKE_CXX_FLAGS="-Ofast -march=native -mtune=native -flto -funroll-loops -ffunction-sections -fdata-sections -Wl,--gc-sections" -DCMAKE_INSTALL_PREFIX=./installed ..; \
cmake --build . --config Release --target brotlienc;
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DCMAKE_C_FLAGS="-Ofast -march=native -mtune=native -flto -funroll-loops -ffunction-sections -fdata-sections -Wl,--gc-sections" -DCMAKE_CXX_FLAGS="-Ofast -march=native -mtune=native -flto -funroll-loops -ffunction-sections -fdata-sections -Wl,--gc-sections" -DCMAKE_INSTALL_PREFIX=./installed .. 2>&1 > /dev/null; \
cmake --build . --config Release --target brotlienc 2>&1 > /dev/null;
RUN set -ex; \
#build QuickJS
case "${APP_NGINX_CONFIGURATION}" in \
case "${BUILD_NGINX_CONFIGURATION}" in \
"full") \
cd /; \
git clone https://github.com/bellard/quickjs; \
curl -SL https://github.com/nginx/njs/archive/refs/tags/${BUILD_DEPENDENCY_NJS_VERSION}.tar.gz | tar -zxC /; \
eleven github asset nginx/njs ${BUILD_DEPENDENCY_NJS_VERSION} ${BUILD_DEPENDENCY_NJS_VERSION}.tar.gz; \
cd ${BUILD_DEPENDENCY_QUICKJS_ROOT}; \
CFLAGS='-fPIC -static -static-libgcc' make libquickjs.a; \
CFLAGS='-fPIC -static -static-libgcc' make libquickjs.a 2>&1 > /dev/null; \
;; \
esac;
RUN set -ex; \
#build XLST
case "${APP_NGINX_CONFIGURATION}" in \
case "${BUILD_NGINX_CONFIGURATION}" in \
"full") \
cd /; \
curl -SL https://download.gnome.org/sources/libxml2/2.14/libxml2-2.14.1.tar.xz | tar -xJC /; \
curl -SL https://download.gnome.org/sources/libxslt/1.1/libxslt-1.1.43.tar.xz | tar -xJC /; \
eleven asset sha256-sum https://download.gnome.org/sources/libxml2/2.14/libxml2-2.14.1.tar.xz https://download.gnome.org/sources/libxml2/2.14/libxml2-2.14.1.sha256sum; \
eleven asset sha256-sum https://download.gnome.org/sources/libxslt/1.1/libxslt-1.1.43.tar.xz https://download.gnome.org/sources/libxslt/1.1/libxslt-1.1.43.sha256sum; \
cd /libxml2-2.14.1; \
./configure \
--prefix="/usr" \
--disable-shared \
--enable-static \
--without-python; \
make -s -j $(nproc); \
make -s -j $(nproc) 2>&1 > /dev/null; \
make install; \
cd /libxslt-1.1.43; \
./configure \
@@ -128,13 +161,13 @@ ARG APP_GID=1000
--disable-shared \
--enable-static \
--without-python; \
make -s -j $(nproc); \
make -s -j $(nproc) 2>&1 > /dev/null; \
make install; \
;; \
esac;
RUN set -ex; \
case "${APP_NGINX_CONFIGURATION}" in \
case "${BUILD_NGINX_CONFIGURATION}" in \
"light") \
cd ${BUILD_ROOT}; \
./configure \
@@ -142,10 +175,10 @@ ARG APP_GID=1000
--with-pcre=${BUILD_DEPENDENCY_PCRE2_ROOT} \
--add-module=${BUILD_DEPENDENCY_HEADERS_MORE_ROOT} \
--add-module=${BUILD_DEPENDENCY_BROTLI_ROOT} \
--prefix=${NGINX_PREFIX} \
--prefix=${BUILD_NGINX_PREFIX} \
--sbin-path=${BUILD_BIN} \
--modules-path=${APP_ROOT}/lib/modules \
--conf-path=${NGINX_PREFIX}/nginx.conf \
--conf-path=${BUILD_NGINX_PREFIX}/nginx.conf \
--error-log-path=${APP_ROOT}/log/error.log \
--http-log-path=${APP_ROOT}/log/access.log \
--pid-path=${APP_ROOT}/run/nginx.pid \
@@ -197,10 +230,10 @@ ARG APP_GID=1000
--add-module=${BUILD_DEPENDENCY_BROTLI_ROOT} \
--add-module=${BUILD_DEPENDENCY_NJS_ROOT}/nginx \
--with-openssl=${BUILD_DEPENDENCY_OPENSSL_ROOT} \
--prefix=${NGINX_PREFIX} \
--prefix=${BUILD_NGINX_PREFIX} \
--sbin-path=${BUILD_BIN} \
--modules-path=${APP_ROOT}/lib/modules \
--conf-path=${NGINX_PREFIX}/nginx.conf \
--conf-path=${BUILD_NGINX_PREFIX}/nginx.conf \
--error-log-path=${APP_ROOT}/log/error.log \
--http-log-path=${APP_ROOT}/log/access.log \
--pid-path=${APP_ROOT}/run/nginx.pid \
@@ -246,72 +279,68 @@ ARG APP_GID=1000
RUN set -ex; \
cd ${BUILD_ROOT}; \
make -s -j $(nproc); \
eleven checkStatic ${BUILD_BIN};
make -s -j $(nproc);
RUN set -ex; \
mkdir -p /distroless/usr/local/bin; \
mkdir -p /distroless${NGINX_PREFIX}; \
cp -R ${BUILD_ROOT}/conf/* /distroless${NGINX_PREFIX}; \
rm /distroless${NGINX_PREFIX}/nginx.conf; \
eleven strip ${BUILD_BIN}; \
cp ${BUILD_BIN} /distroless/usr/local/bin;
COPY ./rootfs/etc /distroless/etc
# :: Distroless / nginx
FROM scratch AS distroless-nginx
COPY --from=build /distroless/ /
# :: Build / file system
FROM alpine AS fs
ARG APP_ROOT
USER root
eleven distroless ${BUILD_BIN};
RUN set -ex; \
mkdir -p ${APP_ROOT}/etc; \
mkdir -p ${APP_ROOT}/var; \
mkdir -p ${APP_ROOT}/run; \
mkdir -p ${APP_ROOT}/lib/modules; \
mkdir -p ${APP_ROOT}/cache; \
mkdir -p ${APP_ROOT}/log; \
ln -sf /dev/stdout ${APP_ROOT}/log/access.log; \
ln -sf /dev/stderr ${APP_ROOT}/log/error.log;
mkdir -p /distroless${BUILD_NGINX_PREFIX}; \
cp -R ${BUILD_ROOT}/conf/* /distroless${BUILD_NGINX_PREFIX}; \
rm /distroless${BUILD_NGINX_PREFIX}/nginx.conf;
COPY ./rootfs/nginx ${APP_ROOT}
COPY ./rootfs/etc/nginx/ /distroless${BUILD_NGINX_PREFIX}
# :: Distroless / file system
FROM scratch AS distroless-fs
RUN set -ex; \
ls -lah /distroless${BUILD_NGINX_PREFIX}; \
cat /distroless${BUILD_NGINX_PREFIX}/nginx.conf;
# :: FILE-SYSTEM
FROM alpine AS file-system
ARG APP_ROOT
COPY --from=fs ${APP_ROOT} /${APP_ROOT}
COPY ./rootfs/nginx /distroless${APP_ROOT}
RUN set -ex; \
mkdir -p /distroless${APP_ROOT}/etc; \
mkdir -p /distroless${APP_ROOT}/var; \
mkdir -p /distroless${APP_ROOT}/run; \
mkdir -p /distroless${APP_ROOT}/lib/modules; \
mkdir -p /distroless${APP_ROOT}/cache; \
mkdir -p /distroless${APP_ROOT}/log; \
ln -sf /dev/stdout /distroless${APP_ROOT}/log/access.log; \
ln -sf /dev/stderr /distroless${APP_ROOT}/log/error.log;
# :: Header
FROM 11notes/distroless AS distroless
FROM 11notes/distroless:curl AS distroless-curl
# ╔═════════════════════════════════════════════════════╗
# ║ IMAGE ║
# ╚═════════════════════════════════════════════════════╝
# :: HEADER
FROM scratch
# :: arguments
ARG TARGETARCH
ARG APP_IMAGE
ARG APP_NAME
ARG APP_VERSION
ARG APP_ROOT
ARG APP_UID
ARG APP_GID
# :: default arguments
ARG TARGETPLATFORM \
TARGETOS \
TARGETARCH \
TARGETVARIANT \
APP_IMAGE \
APP_NAME \
APP_VERSION \
APP_ROOT \
APP_UID \
APP_GID \
APP_NO_CACHE
# :: environment
ENV APP_IMAGE=${APP_IMAGE}
ENV APP_NAME=${APP_NAME}
ENV APP_VERSION=${APP_VERSION}
ENV APP_ROOT=${APP_ROOT}
# :: default environment
ENV APP_IMAGE=${APP_IMAGE} \
APP_NAME=${APP_NAME} \
APP_VERSION=${APP_VERSION} \
APP_ROOT=${APP_ROOT}
# :: multi-stage
COPY --from=distroless --chown=${APP_UID}:${APP_GID} / /
COPY --from=distroless-fs --chown=${APP_UID}:${APP_GID} / /
COPY --from=distroless-curl --chown=${APP_UID}:${APP_GID} / /
COPY --from=distroless-nginx --chown=${APP_UID}:${APP_GID} / /
COPY --from=distroless / /
COPY --from=distroless-curl / /
COPY --from=build /distroless/ /
COPY --from=file-system --chown=${APP_UID}:${APP_GID} /distroless/ /
# :: Volumes
VOLUME ["${APP_ROOT}/etc", "${APP_ROOT}/var"]

192
key.txt Normal file
View File

@@ -0,0 +1,192 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBGZXLBYBEACxv3nUIdUtFCpH1G4hBB+eVSsWwnHVTDtSYfINHmN8dQfyGy22
XcX2DR6ZW9/I5e06McAz4e3hTuhD5+sF7zv4Dd/xEqxpra08liVvB3QlJ6kawBJa
Bn29s/N/A06yUrOVC1ZjhpDLshaHeyHjWDVLUX9ibLx1N3BQoeoH/5lgTmfF4JPk
LfnTMwHWQ5phT52MVE+B/XExldIPAn27m2ZfXHXnSUMKCRybQNypBiIp6OBfirwa
pyjaRO1AajwalSkbSV9o/fL3liluv1HimQ11/5y0rxMdi+aaeca9oA4Gvfdh/biO
MYcTeiZx72BKqDwMfJVXSjQ8XOYbfCjWp8dNkS5Yd4bmX+ITXRkZHqQxgmoKWr7B
9/i+asColt/qqsQ6PROa2y86TbQSfn/HM8L6c85BkJrI41abJ2QHShVzpk0e/464
hqxvnAZCrmdM+GBSuYfDDqHHHgxhIzHnKnyRX/MtfhZA/CUFUOe+m6j214KKtkMQ
6EpZzgH52FFD6Vi1NkQvfYx5pqEdmJfRKR9ABf8fYI8U8ryNgIq7f13bwoX4haZy
ql/fC4lTG6OEppgdQe7afyAmdi7G/w1pMcbz5Wwp91R+1372XifynBdeTrUsbK25
P42TH3OADC2Id+MaaGh1AjY1bFifOGRf48rnrcMn0Q4Lw3l56wgjou4MUQARAQAB
tCtuZ2lueCBzaWduaW5nIGtleSA8c2lnbmluZy1rZXktMkBuZ2lueC5jb20+iQIi
BBMBCgAWBQJmVywWCRAv0hMQtJ9rRgIbAwIZAQAAq08P/jeIVEj9/cJFzdOeBqjg
F9DNZljkR+2z5UAkQSHfkzWgHRbdAnjT1bc/ltLi6w/z/97kOZhaiSx6TLRg2mX/
5nuC4KijhT9rNc/d5j/BHS4U7lFK8c5ED5wxGvJZcF0VCSfeaiuxoO3QiNYX1iiD
qEyJ1XL/XHd7LjJ4gKxsohKL1rRLSuvtOkK799YArNit5ueATDWW6EUSZaxOiMNz
MaQFMEkjoiPVlj7jNwZN7KHNXkaJjiER0kmJ9XWDtkgSHOZrUNX2PHJpxxCtQj7d
YpOFM/DHvNUZ9dHXm3Ioo3R/MUcC4mbZpAvs4YwZ/yRqov/MX4WEUtvcCY36EL5t
hUDK09huMMBLBdM0jgVLsJnXn5ksMdVkpgFyeR/SKEaUTmQrgkCIwqvRxDegAkNN
lmAiNhxdKD+CrWws+EzQYOeWVRUO9aHKC5ttwhhQuxyvmNgoAMhd8x8Tcm7grC/m
ZOqYWzpEWd1DEyi9jaTkhrSWMd5jc5lvCwOHDRzVi1HmIJy+cybPbQpkbFY6vj/7
shx2Aa+QKRJs+33Ztg0drc3j+mDk9NJQy0KPIbqee0gy0pmaKNiJOxdIWI6ra3cM
3lh5OG+CGakga1X9YiCWv4/OgDYY/6cFTqEN0wXruFLNZ7P4iowJgPU1KZauvDZl
gfsgBoKJ35Nf6p9PdjcjcyW5iQEzBBABCAAdFiEEcziXMGntP0Q/TTffpk/VsXrb
OagFAmZXLlcACgkQpk/VsXrbOaiWowgAvU9HwLkK74VGjosmPpcjurRowUp+/KOA
HmIro2wQ6JVlUrSL2Rz+RIBJ1BKTgGnVZznkXywXHWK2LI4nL3aDoAuyyrzQk1pj
hO1ZJGJBvh9Zq/kGRgEdlTe2sXVX2G7fr4fhd6BcYYvUBQ5OWR6Hh6uS+G1QVw0y
Lu5Gp+7kyolyH6iYlgvxseche+EIqBPyHe5fyb1t8Zcu1uHoQHj9O90FvJSbq4dR
d0tTlqK1tDklT+Aod2UobBCurn45udjiAKtzH6Bg2dvF/oY4udSC9/HgNPbm7JuY
clEaLukWMdFOCEj9Xr6krHtUh7zTiU6pHvUL2SYMPhsJj6AKZRg52IkBMwQQAQgA
HRYhBFc7/Ws9j7xkEHmmq6v1vYJ72b9iBQJmVz0rAAoJEKv1vYJ72b9iVTwH/Awq
vgnXbJ5mCGbLdQgrDoUYe+1nw/qWbl7Hpn/px55BEIW5S0itI50c9sOS2QFQMdRh
YVqZ+YH4aH5pDNW2kFik4Y+CFoJI9QkrEUx66PYIMu3RVBEE7/HQEwND/IbEAeMg
PpGQdEfEDD8kevlinJTyDXJ3dfBa6HEDpK0wDYrBx3mbHP7ouACsZcxqSdx4kOyv
U2Xvlc5pVRsdvJ7AsVRhRaRdSO8YlqU1Ue/OM/Ejj+GZ1Qo8EDge5887HiY8gcjy
J4FS1n2+3839n990s5xDCFSB1G8KmwgkfbkS6gEpA5wf9nk3tiSPS+HMfjMb50GJ
SayUVrAyUupv/Sxvyo+JAjMEEAEIAB0WIQTWeGzjA9mpAimY3GzIRk1UmvdcCgUC
ZldKbQAKCRDIRk1UmvdcCn6EEACUhtMnJGtrunotTwywt/jfkqexA+lhQ+S9V5eF
IIK6Tlq1asFy0s+twYJBQzTXt+hmL8GrBgeQp26CA8wrbxmnUOrXO1K9ksaXXjj0
SRo9Xr/flCmeFKFRSSVy18UZVwf1vftFwF2lQspU+xZmj7vgr+2vKa3Z+81J8tHw
3/Sc5pt3EGB8GeCiEThe3zr49KpANejy/7feASSS+BBBUbNqnCFImfwLJ2V99mGx
GdejudbTYEXsn6jyVWTeKBcaLM4ArS20O0DJkqBcVC1Ymq+K3AGmKnrLJXDSwaV/
+yv5pyqApf6Lu9tx7wy6upBop8KroB9xiTN5UIiYhwtHBlpOLkmXB7K549CYX34y
aOHJjez8Txn1bDhbCOe8WOnPEDI8V4RQBr0/xePru6lfwSmSriquVuBGZSir6qxA
1folqrEuoF5aEuxFper6yC/zfVP85znqBOh8OaYTGBeb622UswzLTbW4y2M3E9Ws
KhaXzTqXgIn3INCJLCv4CHiGQQB6zN6meGdOkEV0IaZvq3O4iZOAVFmKbN3GZcKT
Kjxq295LNO15c0WCauik3FRjSppyvcAqoCEbr+LVAX3/ZV3oELhQPnkZCuAFQUB+
LKxTcTEIdjFKrPEvDgXLL9CNe747ANcLCV02SRRGYnfQ1aoxJNQlzbFw0unHjyDk
vKcD44kBswQQAQgAHRYhBBPIKmO2A1dhVuMKTqDqmBtmsNlnBQJmV1HlAAoJEKDq
mBtmsNlni3gMALfZSqIL7v66dMyjLQR81G4o6rEAixTuFc3B8xDmWDHKIjmdRMTN
mm2KGz0CG7VjdHSe3oOBYok4fDVS0o636EOxndOHszuB9cfhMMXNDFi4T1xcZCLm
UTdXCH88cagwTf6REsbfuXF8WiFemNNiPzMzLmnTlUe7Va2t+gKD/Q9vSlDLKz66
IZBMdDoAHDKHZTtvwlAKswnpO0cDIeZjO0C1+YFLLSJ1nYQbh6mH+hJvNLimWPKR
ZQCPAa5w0Gutz91cE9nv03yg3FMcjlEgklQ77g/nGGFJnQHAeMhfgUUfPLx1rI9/
5NON5w7Wf3PXOlTYWO25ieUVKESu8dUCFktKRMnzauej2vjnQlMFG0upzw8dhytn
E83WanvRzVynanK38PCNYQ3INsydN3wvJNetHpBdpyPfOa61dOUtu1TBvV80qcBR
wIe6vbWZx0WB59b3KV8Sc68j8OJxF6i3E0IRby4f0hcoqogBkry0NPK/rtL2HHnN
vcV0wl+DODz9hw==
=oWlI
-----END PGP PUBLIC KEY BLOCK-----
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
ozw9yNdOZmnk2Prj7+mBuchbT3BJOQ==
=AgHy
-----END PGP PUBLIC KEY BLOCK-----
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBGZXO1wBEADEm061e/MGo2f7rpSqokI59in/egWbeQE26vwxB7vPu4e7j+cU
Vg3AezwCbf3nVRAE9DpJ+yuB0KVkM/0QszjOEEBuehZYJrUiwMyiY6jAk8xtqjpV
PsOMyZrypoJhwzg/sYNadUPw4UoHJ/xq4wNA2ZG9Xf0l8M3shYJPmKWLz/eefa5V
Ef/toQ7a55l0aJ7XyACTU6dv4bkHHqomDImK2C94s+KyCxaFyz6NgFz25V/j66Am
gB1m6UGGsvP4qYXW+KTsLz9XDvJeLLHWNcqQoyUO5Vs5C3hGozL7kEkyK/1qHcou
XXkeGN365z93ZeK+VdBZKJtsCswPk2wdDBByU9lAUNHYcLHf6S8fwCACeIqJ6LaY
MKmZUN2gR/boTyMERHEA8XnWXTDp7EsSNIc+LkU5AT8yesANcczH5k/XOI4hltJC
piEsSgg9V7FvO4eA2iQWGv/Y4nlUfw3lbRuRFvd7oqVQKlX4iIs++kVCCegBvtNA
1naxPbvTqrC4THvBSSZpOW/y/6XibAr/scCNNW1mEhwm5SPBHq9Sv35p6xKDTcgQ
8o3KLM8tKKt6kokAqlrXk9Nq6LYrZKwg5a9crFF7nCL2xgxZy1OJQVcPuhhZy5WT
WReE5RJdlF5VGRT9nMJ3B4Vlp5luQnMUFYXTAKQd6Cogbb99J4MjDttAlwARAQAB
tCtuZ2lueCBzaWduaW5nIGtleSA8c2lnbmluZy1rZXktM0BuZ2lueC5jb20+iQIi
BBMBCgAWBQJmVztcCRC83NijjYiiswIbAwIZAQAA9FMQAJ/e8F1egZGbRIV6qU/Q
bJD3EsKZZlitQSVXbBpxqDlkD+uzSFATGjiLGvJoTzfpJpJjI7FwrtO74lRkjCl9
wQUNJ+wm2Kod6rEEQc6lWkDsgxpjqAAGVS0lmMf+VPBGQ+kc8S3ZdCOWEeq7nThZ
/xWR+UuQQcz1vCKmEgwTrr5MJVcqDg4wiH1Z4lRVfjTezf9IWk+xeE3mV8h7Ltbr
N5ZvOkiw88JLrbQsurxx+lYEaGIZyIk3huiDE/KpsMdw9KXUfoDcBqWc7oDjqKL+
QEaq7TW6VetKyJaakP6Do+Opx0BtS3eH86PEZqtULEw9WifC86GtRr50iTXWBTfI
MFZo4AwigHXvZ5WrJvLfldY+scoU1rPMouYlZJ9W+6YHLjf/jpr4W1w6LKKXX3ah
h4VLtlOmrOLA21E7RQ0PwoE6nT7DAm1DsMFCXy7lyp3u5IXGahnJddWCb0Px3RTm
PZgOt+YAGJDsP46ngl5LxhilMK5f5R8v5n1lJ/XzFcXCEN4i/d8A1jx9DQx4CJN1
wp/WZzJ6GjnCqMCdOBlQ2eNmhR+q1bAI79kSv86ahaM/aS1FvHMz8ppzwkRhv5jY
eR9aRlAwaCPOjbWhYJt/xveOWmxCdg5ta+Pj5g+41wHZyNf9aqR314aKwsxo2AYH
uUe+PgpsHbe1sQTkb/W1OfSCiQEzBBABCAAdFiEEcziXMGntP0Q/TTffpk/VsXrb
OagFAmZXO+kACgkQpk/VsXrbOajGgwf8CAXJwSIhGOWFSgV6vpvZPChTsgteZxhT
8NrJJLxL8X34Rw5YctSli4akkchTonm5RRp/SlvI2fPe0o6q2ymF4BASPJ/oSI3p
Gs/jwctHz8hwaVN0xQ4SBXgquIFWrLRNOjCxEV/vMRJRzuF9jrrdv3vxZEugETI+
rnoEZu2Z2ZlMj7PPeiScf8dFXax67+Xi5S2KJCaXm1QGAJvttHrwsbBAIE9CVUg4
UmXwADQ6HkOKjY+QS5AP8Ak1dg8/oadgyMqB4GrcE44KUpo4YafP37XnwXfQNKpk
Rb0bO9Qm9lM/LhPulBY8WIPkmrFCVhGTE6K5ZvI59R4nECHHx24/LYkBMwQQAQgA
HRYhBFc7/Ws9j7xkEHmmq6v1vYJ72b9iBQJmVzzzAAoJEKv1vYJ72b9iPPIIAJ5k
hTz2d7CaJefHzoraogKSIeBnA3OR+nDgdDl9Mp8i2WLGu9YYhIrPU0iSVw8jqa8t
GIjCw4/bS9HN8oub2Ip802xDLugCz1Yz6CXjCXN2rlNPsdBV8IIKNHOv93qMvnZS
DwyBUAvAs4XzF7zbYgfZ30B0gRI0g0+Nt44oDOn3PfO/kNUJyBVPT9m7l3JUHuZT
FPOD8a0oJPvW+iYlSkmPELBvgehsX7MVLoeQ5qtS1KkuWr+y1wqD5kxqabMPcfdU
jAr4ssXs/pSsYJVyS4CuUWkY4FiCJm4KtU+XPDs1RCTzMkW6HHgSebocTZzLETYw
XsDx80qd21UAdGc116qJAjMEEAEIAB0WIQTWeGzjA9mpAimY3GzIRk1UmvdcCgUC
ZldKYgAKCRDIRk1UmvdcCoG/D/9qLmHYOGnsmedUbgtLmuBJOuA6oqnaWxYI45eV
+vaAaI2+QfRoJTrjklTXv29Pi4LTzN5YBySSIkv/z9ry5Xsz5yroNY9Xb6JdrqOt
fLa/U0wddNuJbmIom4gUPXGInhHUBbP6mNz+s6e2ukBEWvb2XIsGe5v291QXMohQ
/PT8zTIwNYaw2zVF6Sa/0spA9/9XA5BdUcrtl7xPgYL7pLVmKYGJlCf5TOaWfLDJ
mIMeeUznVK9vK+vT+YqUPfFyIqO7dvio/+MRFjePoD6csT4UBT009ugy8vrYg2YR
K9uaRxP3laz9b6xdUM648ycUQLoI4fLhyKAHwPU9/Q+4rOFdrL72ZGVKzv1XOB0H
VXf0/E4JmJBydM7AyXHNxIPDtNFydosGn6VZsEvSPZdQSCsCeBs9UuBWgwFb1XBB
61XiHGnheb3U3ZRkajS1ZNdxfohHrBzHnd8tbDkv5Rq+XoUmDauoeM0VcN15hl4a
M/JzkeOrHuJicn3mg+HRHxQSCl3D37bVQT7O36n7cff22GykT7XQUBBxMlhKzygD
SgdQUtSEt0eu7AXIvr6yl0kobgZQS3wzUIaY0JEuv2ahtEXXjoPzCVWB2OHIpPbu
D58cpyyEVqr+ZecaI4HlaO9lVShf+K0rf/6DC12rC2gNzzv/fCIinDiqiMsPTfEM
fduRSYkBswQQAQgAHRYhBBPIKmO2A1dhVuMKTqDqmBtmsNlnBQJmV1HlAAoJEKDq
mBtmsNlnhI4L/0MHtfCZ2nuKTF/BkxJ7oB3Uule0tWiFj5SU97GjcVj1LgawGY7Y
+zoyEd6Twpl6H/+QkZBB55Bf8+cTzRbDzH1Og0fSORu0pGC0uxWdYu1sTLeTnn93
mesXAvevHFNbsPchIWwsVJopTdzMWuAQS5hMMMtNb/14ZfnBadzhjvaJeH3DlZVK
0cGFp0qfbMfjr9yRJzQ1IkiXsS4G4uKg9T+KRsPr4+JalurWJgLnBXZGetNNjjUa
UCV1KZY/iWCAlZjkZ5z7yBRj5nUWLb5AVouEQPEDbn+i/0uEjukC+G6EMq2mgbrh
m0bFHbHAYBaf9EH0eP799HpoAx2aziDB5igAC516i3BnqxINI9mXHh92tU/H797I
oYZvpBsAHDWDHj6O74jwk5lXF5Qwri8gjA8aTudmuQX3uX4h0/FyGGQJW4/wWecH
/1fMuvHHyRtOSsJsheDwcSjrw5WlsyNjvSIbBPV2fIx60W2haVMUVX6CrxAeq44F
UYda9m8fOnaIew==
=TEOn
-----END PGP PUBLIC KEY BLOCK-----

View File

@@ -1,17 +1,19 @@
${{ content_synopsis }} This image will serve as a base for nginx related images that need a high-performance webserver. The default tag of this image is stripped for most functions that can be used by a reverse proxy in front of nginx, it adds however important webserver functions like brotli compression. The default tag is not meant to run as a reverse proxy, use the full image for that. The default tag does not support HTTPS for instance!
${{ content_synopsis }} This image will serve as a base for nginx related images that need a high-performance webserver. The default tag of this image is stripped for most functions that can be used by a reverse proxy in front of nginx, it adds however important webserver functions like brotli compression. The default tag is not meant to run as a reverse proxy, use the full image for that. **The default tag does not support HTTPS for instance!**
${{ content_uvp }} Good question! All the other images on the market that do exactly the same dont do or offer these options:
${{ content_uvp }} Good question! Because ...
${{ github:> [!IMPORTANT] }}
${{ github:> }}* This image runs as 1000:1000 by default, most other images run everything as root
${{ github:> }}* This image has no shell since it is 100% distroless, most other images run on a distro like Debian or Alpine with full shell access (security)
${{ github:> }}* This image does not ship with any critical or high rated CVE and is automatically maintained via CI/CD, most other images mostly have no CVE scanning or code quality tools in place
${{ github:> }}* This image is created via a secure, pinned CI/CD process and immune to upstream attacks, most other images have upstream dependencies that can be exploited
${{ github:> }}* This image contains a proper health check that verifies the app is actually working, most other images have either no health check or only check if a port is open or ping works
${{ github:> }}* This image works as read-only, most other images need to write files to the image filesystem
${{ github:> }}* This image is a lot smaller than most other images
${{ github:> }}* ... this image runs [rootless](https://github.com/11notes/RTFM/blob/main/linux/container/image/rootless.md) as 1000:1000
${{ github:> }}* ... this image has no shell since it is [distroless](https://github.com/11notes/RTFM/blob/main/linux/container/image/distroless.md)
${{ github:> }}* ... this image is auto updated to the latest version via CI/CD
${{ github:> }}* ... this image has a health check
${{ github:> }}* ... this image runs read-only
${{ github:> }}* ... this image is automatically scanned for CVEs before and after publishing
${{ github:> }}* ... this image is created via a secure and pinned CI/CD process
${{ github:> }}* ... this image verifies external payloads if possible
${{ github:> }}* ... this image is very small
If you value security, simplicity and the ability to interact with the maintainer and developer of an image. Using my images is a great start in that direction.
If you value security, simplicity and optimizations to the extreme, then this image might be for you.
${{ content_comparison }}