[breaking] switch to distroless and static binary
This commit is contained in:
@@ -5,3 +5,6 @@ LICENSE
|
||||
*.md
|
||||
img/
|
||||
node_modules/
|
||||
|
||||
# custom
|
||||
.env
|
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -1,2 +1,3 @@
|
||||
# default
|
||||
* text=auto
|
||||
*.sh eol=lf
|
206
.github/workflows/docker.yml
vendored
206
.github/workflows/docker.yml
vendored
@@ -10,6 +10,12 @@ on:
|
||||
required: false
|
||||
default: 'docker'
|
||||
|
||||
runs-on:
|
||||
description: 'set runs-on for workflow (github or selfhosted)'
|
||||
type: string
|
||||
required: false
|
||||
default: 'ubuntu-22.04'
|
||||
|
||||
release:
|
||||
description: 'set WORKFLOW_GITHUB_RELEASE'
|
||||
required: false
|
||||
@@ -20,29 +26,14 @@ on:
|
||||
required: false
|
||||
default: 'false'
|
||||
|
||||
image:
|
||||
description: 'set IMAGE'
|
||||
required: false
|
||||
|
||||
uid:
|
||||
description: 'set IMAGE_UID'
|
||||
required: false
|
||||
|
||||
gid:
|
||||
description: 'set IMAGE_GID'
|
||||
required: false
|
||||
|
||||
semverprefix:
|
||||
description: 'prefix for semver tags'
|
||||
required: false
|
||||
|
||||
semversuffix:
|
||||
description: 'suffix for semver tags'
|
||||
etc:
|
||||
description: 'base64 encoded json string'
|
||||
required: false
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ${{ inputs.runs-on }}
|
||||
timeout-minutes: 1440
|
||||
|
||||
services:
|
||||
registry:
|
||||
@@ -69,12 +60,17 @@ jobs:
|
||||
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');
|
||||
@@ -95,27 +91,30 @@ jobs:
|
||||
core.setFailed(e);
|
||||
}
|
||||
|
||||
core.info(inspect(opt, {showHidden:false, depth:null, colors:true}));
|
||||
|
||||
const docker = {
|
||||
image:{
|
||||
name:(opt.input?.image || opt.dot.image),
|
||||
name:opt.dot.image,
|
||||
arch:(opt.dot.arch || 'linux/amd64,linux/arm64'),
|
||||
prefix:((opt.input?.semverprefix) ? `${opt.input?.semverprefix}-` : ''),
|
||||
suffix:((opt.input?.semversuffix) ? `-${opt.input?.semversuffix}` : ''),
|
||||
prefix:((opt.input?.etc?.semverprefix) ? `${opt.input?.etc?.semverprefix}-` : ''),
|
||||
suffix:((opt.input?.etc?.semversuffix) ? `-${opt.input?.etc?.semversuffix}` : ''),
|
||||
description:(opt.dot?.readme?.description || ''),
|
||||
tags:[],
|
||||
},
|
||||
app:{
|
||||
image:opt.dot.image,
|
||||
name:opt.dot.name,
|
||||
version:opt.dot.semver.version,
|
||||
version:(opt.input?.etc?.version || opt.dot.semver.version),
|
||||
root:opt.dot.root,
|
||||
UID:(opt.input?.uid || 1000),
|
||||
GID:(opt.input?.gid || 1000),
|
||||
UID:(opt.input?.etc?.uid || 1000),
|
||||
GID:(opt.input?.etc?.gid || 1000),
|
||||
no_cache:new Date().getTime(),
|
||||
},
|
||||
cache:{
|
||||
registry:'localhost:5000/',
|
||||
}
|
||||
},
|
||||
tags:[],
|
||||
};
|
||||
|
||||
docker.cache.name = `${docker.image.name}:${docker.image.prefix}buildcache${docker.image.suffix}`;
|
||||
@@ -124,21 +123,37 @@ jobs:
|
||||
docker.app.suffix = docker.image.suffix;
|
||||
|
||||
// setup tags
|
||||
const semver = opt.dot.semver.version.split('.');
|
||||
docker.image.tags.push(`${context.sha.substring(0,7)}`);
|
||||
if(Array.isArray(semver)){
|
||||
if(semver.length >= 1) docker.image.tags.push(`${semver[0]}`);
|
||||
if(semver.length >= 2) docker.image.tags.push(`${semver[0]}.${semver[1]}`);
|
||||
if(semver.length >= 3) docker.image.tags.push(`${semver[0]}.${semver[1]}.${semver[2]}`);
|
||||
if(opt.input?.etc?.dockerfile !== 'arch.dockerfile' && opt.input?.etc?.tag){
|
||||
docker.image.tags.push(`${context.sha.substring(0,7)}`);
|
||||
docker.image.tags.push(opt.input.etc.tag);
|
||||
docker.image.tags.push(`${opt.input.etc.tag}-${docker.app.version}`);
|
||||
docker.cache.name = `${docker.image.name}:buildcache-${opt.input.etc.tag}`;
|
||||
}else if(opt.dot?.semver?.version){
|
||||
const semver = opt.dot.semver.version.split('.');
|
||||
docker.image.tags.push(`${context.sha.substring(0,7)}`);
|
||||
if(Array.isArray(semver)){
|
||||
if(semver.length >= 1) docker.image.tags.push(`${semver[0]}`);
|
||||
if(semver.length >= 2) docker.image.tags.push(`${semver[0]}.${semver[1]}`);
|
||||
if(semver.length >= 3) docker.image.tags.push(`${semver[0]}.${semver[1]}.${semver[2]}`);
|
||||
}
|
||||
if(opt.dot.semver?.stable && new RegExp(opt.dot.semver.stable, 'ig').test(docker.image.tags.join(','))) docker.image.tags.push('stable');
|
||||
if(opt.dot.semver?.latest && new RegExp(opt.dot.semver.latest, 'ig').test(docker.image.tags.join(','))) docker.image.tags.push('latest');
|
||||
}else if(opt.input?.etc?.version && opt.input.etc.version === 'latest'){
|
||||
docker.image.tags.push('latest');
|
||||
}
|
||||
if(opt.dot.semver?.stable && new RegExp(opt.dot.semver.stable, 'ig').test(docker.image.tags.join(','))) docker.image.tags.push('stable');
|
||||
if(opt.dot.semver?.latest && new RegExp(opt.dot.semver.latest, 'ig').test(docker.image.tags.join(','))) docker.image.tags.push('latest');
|
||||
|
||||
for(let i=0; i<docker.image.tags.length; i++){
|
||||
docker.image.tags[i] = `${docker.image.name}:${docker.image.prefix}${docker.image.tags[i]}${docker.image.suffix}`;
|
||||
for(const tag of docker.image.tags){
|
||||
docker.tags.push(`${docker.image.name}:${docker.image.prefix}${tag}${docker.image.suffix}`);
|
||||
docker.tags.push(`ghcr.io/${docker.image.name}:${docker.image.prefix}${tag}${docker.image.suffix}`);
|
||||
docker.tags.push(`quay.io/${docker.image.name}:${docker.image.prefix}${tag}${docker.image.suffix}`);
|
||||
}
|
||||
|
||||
// setup build arguments
|
||||
if(opt.input?.etc?.build?.args){
|
||||
for(const arg in opt.input.etc.build.args){
|
||||
docker.app[arg] = opt.input.etc.build.args[arg];
|
||||
}
|
||||
}
|
||||
const arguments = [];
|
||||
for(const argument in docker.app){
|
||||
arguments.push(`APP_${argument.toUpperCase()}=${docker.app[argument]}`);
|
||||
@@ -151,24 +166,39 @@ jobs:
|
||||
|
||||
core.exportVariable('DOCKER_IMAGE_NAME', docker.image.name);
|
||||
core.exportVariable('DOCKER_IMAGE_ARCH', docker.image.arch);
|
||||
core.exportVariable('DOCKER_IMAGE_TAGS', docker.image.tags.join(','));
|
||||
core.exportVariable('DOCKER_IMAGE_TAGS', docker.tags.join(','));
|
||||
core.exportVariable('DOCKER_IMAGE_DESCRIPTION', docker.image.description);
|
||||
core.exportVariable('DOCKER_IMAGE_ARGUMENTS', arguments.join("\r\n"));
|
||||
core.exportVariable('DOCKER_IMAGE_DOCKERFILE', opt.input?.etc?.dockerfile || 'arch.dockerfile');
|
||||
|
||||
core.exportVariable('WORKFLOW_CREATE_RELEASE', (opt.input?.release || true));
|
||||
core.exportVariable('WORKFLOW_CREATE_README', (opt.input?.readme || true));
|
||||
core.exportVariable('WORKFLOW_GRYPE_FAIL_ON_SEVERITY', (opt.json?.grpye?.fail || true));
|
||||
core.exportVariable('WORKFLOW_GRYPE_SEVERITY_CUTOFF', (opt.json?.grpye?.severity || 'high'));
|
||||
core.exportVariable('WORKFLOW_CREATE_RELEASE', (opt.input?.release === undefined) ? false : opt.input.release);
|
||||
core.exportVariable('WORKFLOW_CREATE_README', (opt.input?.readme === undefined) ? false : opt.input.readme);
|
||||
core.exportVariable('WORKFLOW_GRYPE_FAIL_ON_SEVERITY', (opt.dot?.grype?.fail === undefined) ? true : opt.dot.grype.fail);
|
||||
core.exportVariable('WORKFLOW_GRYPE_SEVERITY_CUTOFF', (opt.dot?.grype?.severity || 'high'));
|
||||
|
||||
|
||||
|
||||
# DOCKER
|
||||
- name: docker / login to hub
|
||||
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567
|
||||
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772
|
||||
with:
|
||||
username: 11notes
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
|
||||
- name: github / login to ghcr
|
||||
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: 11notes
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: quay / login to quay
|
||||
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772
|
||||
with:
|
||||
registry: quay.io
|
||||
username: 11notes+github
|
||||
password: ${{ secrets.QUAY_TOKEN }}
|
||||
|
||||
- name: docker / setup qemu
|
||||
uses: docker/setup-qemu-action@53851d14592bedcffcf25ea515637cff71ef929a
|
||||
|
||||
@@ -182,7 +212,7 @@ jobs:
|
||||
uses: docker/build-push-action@67a2d409c0a876cbe6b11854e3e25193efe4e62d
|
||||
with:
|
||||
context: .
|
||||
file: arch.dockerfile
|
||||
file: ${{ env.DOCKER_IMAGE_DOCKERFILE }}
|
||||
push: true
|
||||
platforms: ${{ env.DOCKER_IMAGE_ARCH }}
|
||||
cache-from: type=registry,ref=${{ env.DOCKER_CACHE_NAME }}
|
||||
@@ -194,7 +224,7 @@ jobs:
|
||||
|
||||
- name: grype / scan
|
||||
id: grype
|
||||
uses: anchore/scan-action@abae793926ec39a78ab18002bc7fc45bbbd94342
|
||||
uses: anchore/scan-action@dc6246fcaf83ae86fcc6010b9824c30d7320729e
|
||||
with:
|
||||
image: ${{ env.DOCKER_CACHE_GRYPE }}
|
||||
fail-build: ${{ env.WORKFLOW_GRYPE_FAIL_ON_SEVERITY }}
|
||||
@@ -205,7 +235,7 @@ jobs:
|
||||
|
||||
- name: grype / fail
|
||||
if: failure() || steps.grype.outcome == 'failure'
|
||||
uses: anchore/scan-action@abae793926ec39a78ab18002bc7fc45bbbd94342
|
||||
uses: anchore/scan-action@dc6246fcaf83ae86fcc6010b9824c30d7320729e
|
||||
with:
|
||||
image: ${{ env.DOCKER_CACHE_GRYPE }}
|
||||
fail-build: false
|
||||
@@ -218,7 +248,7 @@ jobs:
|
||||
uses: docker/build-push-action@67a2d409c0a876cbe6b11854e3e25193efe4e62d
|
||||
with:
|
||||
context: .
|
||||
file: arch.dockerfile
|
||||
file: ${{ env.DOCKER_IMAGE_DOCKERFILE }}
|
||||
push: true
|
||||
sbom: true
|
||||
provenance: mode=max
|
||||
@@ -250,6 +280,12 @@ jobs:
|
||||
if: env.WORKFLOW_CREATE_RELEASE == 'true' && steps.git-log.outcome == 'success'
|
||||
id: git-release
|
||||
uses: 11notes/action-docker-release@v1
|
||||
# WHY IS THIS ACTION NOT SHA256 PINNED? SECURITY MUCH?!?!?!
|
||||
# ---------------------------------------------------------------------------------
|
||||
# the next step "github / release / create" creates a new release based on the code
|
||||
# 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 }}
|
||||
|
||||
@@ -267,6 +303,35 @@ jobs:
|
||||
|
||||
|
||||
|
||||
|
||||
# LICENSE
|
||||
- name: license / update year
|
||||
continue-on-error: true
|
||||
uses: actions/github-script@62c3794a3eb6788d9a2a72b219504732c0c9a298
|
||||
with:
|
||||
script: |
|
||||
const { existsSync, readFileSync, writeFileSync } = require('node:fs');
|
||||
const { resolve } = require('node:path');
|
||||
const file = 'LICENSE';
|
||||
const year = new Date().getFullYear();
|
||||
try{
|
||||
const path = resolve(file);
|
||||
if(existsSync(path)){
|
||||
let license = readFileSync(file).toString();
|
||||
if(!new RegExp(`Copyright \\(c\\) ${year} 11notes`, 'i').test(license)){
|
||||
license = license.replace(/Copyright \(c\) \d{4} /i, `Copyright (c) ${new Date().getFullYear()} `);
|
||||
writeFileSync(path, license);
|
||||
}
|
||||
}else{
|
||||
throw new Error(`file ${file} does not exist`);
|
||||
}
|
||||
}catch(e){
|
||||
core.setFailed(e);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
# README
|
||||
- name: github / checkout master
|
||||
continue-on-error: true
|
||||
@@ -278,23 +343,20 @@ jobs:
|
||||
continue-on-error: true
|
||||
if: env.WORKFLOW_CREATE_README == 'true' && steps.docker-build.outcome == 'success'
|
||||
uses: 11notes/action-docker-readme@v1
|
||||
# WHY IS THIS ACTION NOT SHA256 PINNED? SECURITY MUCH?!?!?!
|
||||
# ---------------------------------------------------------------------------------
|
||||
# the next step "github / commit & push" only adds the README and LICENSE as well as
|
||||
# compose.yaml to the repository. This does not pose a security risk if this action
|
||||
# would be compromised. The code of the app can't be changed by this action. Since
|
||||
# only the files mentioned are commited to the repo. Sure, someone could make a bad
|
||||
# compose.yaml, but since this serves only as an example I see no harm in that.
|
||||
with:
|
||||
sarif_file: ${{ steps.grype.outputs.sarif }}
|
||||
build_output_metadata: ${{ steps.docker-build.outputs.metadata }}
|
||||
|
||||
- name: github / commit & push
|
||||
continue-on-error: true
|
||||
if: steps.github-readme.outcome == 'success' && hashFiles('README.md') != ''
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git add README.md
|
||||
git commit -m "auto update README.md"
|
||||
git push
|
||||
|
||||
- name: docker / push README.md to docker hub
|
||||
continue-on-error: true
|
||||
if: steps.github-readme.outcome == 'success' && hashFiles('README.md') != ''
|
||||
if: steps.github-readme.outcome == 'success' && hashFiles('README_NONGITHUB.md') != ''
|
||||
uses: christian-korneck/update-container-description-action@d36005551adeaba9698d8d67a296bd16fa91f8e8
|
||||
env:
|
||||
DOCKER_USER: 11notes
|
||||
@@ -303,7 +365,35 @@ jobs:
|
||||
destination_container_repo: ${{ env.DOCKER_IMAGE_NAME }}
|
||||
provider: dockerhub
|
||||
short_description: ${{ env.DOCKER_IMAGE_DESCRIPTION }}
|
||||
readme_file: 'README.md'
|
||||
readme_file: 'README_NONGITHUB.md'
|
||||
|
||||
- name: quay / push README.md to quay
|
||||
continue-on-error: true
|
||||
if: steps.github-readme.outcome == 'success' && hashFiles('README_NONGITHUB.md') != ''
|
||||
uses: christian-korneck/update-container-description-action@d36005551adeaba9698d8d67a296bd16fa91f8e8
|
||||
env:
|
||||
DOCKER_APIKEY: ${{ secrets.QUAY_TOKEN }}
|
||||
with:
|
||||
destination_container_repo: quay.io/${{ env.DOCKER_IMAGE_NAME }}
|
||||
provider: quay
|
||||
readme_file: 'README_NONGITHUB.md'
|
||||
|
||||
- name: github / commit & push
|
||||
continue-on-error: true
|
||||
if: steps.github-readme.outcome == 'success' && hashFiles('README.md') != ''
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git add README.md
|
||||
if [ -f compose.yaml ]; then
|
||||
git add compose.yaml
|
||||
fi
|
||||
if [ -f LICENSE ]; then
|
||||
git add LICENSE
|
||||
fi
|
||||
git commit -m "auto update README.md"
|
||||
git push
|
||||
|
||||
|
||||
|
||||
|
||||
|
36
.github/workflows/full.yml
vendored
Normal file
36
.github/workflows/full.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
name: tags
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'full'
|
||||
jobs:
|
||||
node:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: init / base64 nested json
|
||||
uses: actions/github-script@62c3794a3eb6788d9a2a72b219504732c0c9a298
|
||||
with:
|
||||
script: |
|
||||
const { Buffer } = require('node:buffer');
|
||||
(async()=>{
|
||||
try{
|
||||
const etc = {
|
||||
build:{
|
||||
args:{
|
||||
NGINX_CONFIGURATION:'full',
|
||||
}
|
||||
},
|
||||
semverprefix:'full',
|
||||
};
|
||||
core.exportVariable('WORKFLOW_BASE64JSON', Buffer.from(JSON.stringify(etc)).toString('base64'));
|
||||
}catch(e){
|
||||
core.setFailed(`workflow failed: ${e}`);
|
||||
}
|
||||
})();
|
||||
|
||||
- name: build docker image
|
||||
uses: the-actions-org/workflow-dispatch@3133c5d135c7dbe4be4f9793872b6ef331b53bc7
|
||||
with:
|
||||
workflow: docker.yml
|
||||
token: "${{ secrets.REPOSITORY_TOKEN }}"
|
||||
inputs: '{ "release":"false", "readme":"true", "etc":"${{ env.WORKFLOW_BASE64JSON }}" }'
|
34
.github/workflows/tags.yml
vendored
34
.github/workflows/tags.yml
vendored
@@ -4,22 +4,32 @@ on:
|
||||
tags:
|
||||
- 'v*'
|
||||
jobs:
|
||||
docker:
|
||||
node:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: init / base64 nested json
|
||||
uses: actions/github-script@62c3794a3eb6788d9a2a72b219504732c0c9a298
|
||||
with:
|
||||
script: |
|
||||
const { Buffer } = require('node:buffer');
|
||||
(async()=>{
|
||||
try{
|
||||
const etc = {
|
||||
build:{
|
||||
args:{
|
||||
NGINX_CONFIGURATION:'light',
|
||||
}
|
||||
}
|
||||
};
|
||||
core.exportVariable('WORKFLOW_BASE64JSON', Buffer.from(JSON.stringify(etc)).toString('base64'));
|
||||
}catch(e){
|
||||
core.setFailed(`workflow failed: ${e}`);
|
||||
}
|
||||
})();
|
||||
|
||||
- name: build docker image
|
||||
uses: the-actions-org/workflow-dispatch@3133c5d135c7dbe4be4f9793872b6ef331b53bc7
|
||||
with:
|
||||
workflow: docker.yml
|
||||
token: "${{ secrets.REPOSITORY_TOKEN }}"
|
||||
inputs: '{ "release":"true", "readme":"true" }'
|
||||
|
||||
docker-unraid:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: build docker image for unraid community
|
||||
uses: the-actions-org/workflow-dispatch@3133c5d135c7dbe4be4f9793872b6ef331b53bc7
|
||||
with:
|
||||
workflow: docker.yml
|
||||
token: "${{ secrets.REPOSITORY_TOKEN }}"
|
||||
inputs: '{ "release":"false", "readme":"false", "uid":"99", "gid":"100", "semversuffix":"unraid", "run-name":"docker-unraid" }'
|
||||
inputs: '{ "release":"true", "readme":"true", "etc":"${{ env.WORKFLOW_BASE64JSON }}" }'
|
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,3 +1,6 @@
|
||||
# default
|
||||
maintain/
|
||||
node_modules/
|
||||
|
||||
# custom
|
||||
.env
|
11
.json
11
.json
@@ -10,12 +10,15 @@
|
||||
},
|
||||
|
||||
"readme":{
|
||||
"description":"Nginx with additional plugins and custom compiled",
|
||||
"parent":{
|
||||
"image":"11notes/alpine:stable"
|
||||
},
|
||||
"description":"Nginx, slim and distroless to be used behind a reverse proxy or as full version",
|
||||
"built":{
|
||||
"nginx":"https://nginx.org"
|
||||
},
|
||||
"distroless":{
|
||||
"layers":[
|
||||
"11notes/distroless",
|
||||
"11notes/distroless:curl"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
421
arch.dockerfile
421
arch.dockerfile
@@ -1,100 +1,297 @@
|
||||
ARG APP_UID=1000
|
||||
ARG APP_GID=1000
|
||||
|
||||
# :: Util
|
||||
FROM 11notes/util AS util
|
||||
|
||||
# :: Build / nginx
|
||||
FROM alpine/git AS build
|
||||
ARG APP_VERSION
|
||||
FROM alpine AS build
|
||||
ARG TARGETARCH
|
||||
ARG TARGETPLATFORM
|
||||
ARG TARGETVARIANT
|
||||
ARG APP_ROOT
|
||||
ENV MODULE_HEADERS_MORE_NGINX_VERSION=0.37
|
||||
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}
|
||||
|
||||
USER root
|
||||
|
||||
COPY --from=util /usr/local/bin/ /usr/local/bin
|
||||
|
||||
RUN set -ex; \
|
||||
CONFIG="\
|
||||
--with-cc-opt=-O2 \
|
||||
--prefix=/etc/nginx \
|
||||
--sbin-path=/usr/sbin/nginx \
|
||||
--modules-path=/usr/lib/nginx/modules \
|
||||
--conf-path=/etc/nginx/nginx.conf \
|
||||
--error-log-path=/var/log/nginx/error.log \
|
||||
--http-log-path=/var/log/nginx/access.log \
|
||||
--pid-path=${APP_ROOT}/run/nginx.pid \
|
||||
--lock-path=${APP_ROOT}/run/nginx.lock \
|
||||
--http-client-body-temp-path=${APP_ROOT}/cache/client_temp \
|
||||
--http-proxy-temp-path=${APP_ROOT}/cache/proxy_temp \
|
||||
--http-fastcgi-temp-path=${APP_ROOT}/cache/fastcgi_temp \
|
||||
--http-uwsgi-temp-path=${APP_ROOT}/cache/uwsgi_temp \
|
||||
--http-scgi-temp-path=${APP_ROOT}/cache/scgi_temp \
|
||||
--user=docker \
|
||||
--group=docker \
|
||||
--with-http_ssl_module \
|
||||
--with-http_realip_module \
|
||||
--with-http_addition_module \
|
||||
--with-http_sub_module \
|
||||
--with-http_dav_module \
|
||||
--with-http_flv_module \
|
||||
--with-http_mp4_module \
|
||||
--with-http_gunzip_module \
|
||||
--with-http_gzip_static_module \
|
||||
--with-http_random_index_module \
|
||||
--with-http_secure_link_module \
|
||||
--with-http_stub_status_module \
|
||||
--with-http_auth_request_module \
|
||||
--with-http_xslt_module=dynamic \
|
||||
--with-http_image_filter_module=dynamic \
|
||||
--with-http_geoip_module=dynamic \
|
||||
--with-threads \
|
||||
--with-stream \
|
||||
--with-stream_ssl_module \
|
||||
--with-stream_ssl_preread_module \
|
||||
--with-stream_realip_module \
|
||||
--with-stream_geoip_module=dynamic \
|
||||
--with-http_slice_module \
|
||||
--with-compat \
|
||||
--with-file-aio \
|
||||
--with-http_v2_module \
|
||||
--add-module=/usr/lib/nginx/modules/headers-more-nginx-module-${MODULE_HEADERS_MORE_NGINX_VERSION} \
|
||||
"; \
|
||||
apk add --no-cache --update \
|
||||
curl \
|
||||
tar \
|
||||
gcc \
|
||||
libc-dev \
|
||||
make \
|
||||
openssl-dev \
|
||||
pcre2-dev \
|
||||
zlib-dev \
|
||||
linux-headers \
|
||||
libxslt-dev \
|
||||
gd-dev \
|
||||
geoip-dev \
|
||||
perl-dev \
|
||||
libedit-dev \
|
||||
bash \
|
||||
alpine-sdk \
|
||||
findutils; \
|
||||
apk upgrade; \
|
||||
mkdir -p /usr/lib/nginx/modules; \
|
||||
mkdir -p /usr/src; \
|
||||
curl -SL https://github.com/openresty/headers-more-nginx-module/archive/v${MODULE_HEADERS_MORE_NGINX_VERSION}.tar.gz | tar -zxC /usr/lib/nginx/modules; \
|
||||
curl -SL https://nginx.org/download/nginx-${APP_VERSION}.tar.gz | tar -zxC /usr/src; \
|
||||
cd /usr/src/nginx-${APP_VERSION}; \
|
||||
./configure $CONFIG --with-debug; \
|
||||
make -j $(nproc); \
|
||||
mv objs/nginx objs/nginx-debug; \
|
||||
mv objs/ngx_http_xslt_filter_module.so objs/ngx_http_xslt_filter_module-debug.so; \
|
||||
mv objs/ngx_http_image_filter_module.so objs/ngx_http_image_filter_module-debug.so; \
|
||||
mv objs/ngx_http_geoip_module.so objs/ngx_http_geoip_module-debug.so; \
|
||||
mv objs/ngx_stream_geoip_module.so objs/ngx_stream_geoip_module-debug.so; \
|
||||
./configure $CONFIG; \
|
||||
make -j $(nproc); \
|
||||
make install; \
|
||||
install -m755 objs/ngx_http_xslt_filter_module-debug.so /usr/lib/nginx/modules/ngx_http_xslt_filter_module-debug.so; \
|
||||
install -m755 objs/ngx_http_image_filter_module-debug.so /usr/lib/nginx/modules/ngx_http_image_filter_module-debug.so; \
|
||||
install -m755 objs/ngx_http_geoip_module-debug.so /usr/lib/nginx/modules/ngx_http_geoip_module-debug.so; \
|
||||
install -m755 objs/ngx_stream_geoip_module-debug.so /usr/lib/nginx/modules/ngx_stream_geoip_module-debug.so; \
|
||||
strip /usr/sbin/nginx*; \
|
||||
strip /usr/lib/nginx/modules/*.so;
|
||||
apk --update --no-cache add \
|
||||
cmake \
|
||||
autoconf \
|
||||
automake \
|
||||
git \
|
||||
build-base \
|
||||
curl \
|
||||
tar \
|
||||
gcc \
|
||||
g++ \
|
||||
libc-dev \
|
||||
make \
|
||||
openssl-dev \
|
||||
pcre2-dev \
|
||||
zlib-dev \
|
||||
linux-headers \
|
||||
libxslt-dev \
|
||||
libxslt-static \
|
||||
gd-dev \
|
||||
geoip-dev \
|
||||
perl-dev \
|
||||
libedit-dev \
|
||||
libxml2-dev \
|
||||
libtool \
|
||||
quickjs-dev \
|
||||
quickjs-static \
|
||||
bash \
|
||||
libxml2-static \
|
||||
alpine-sdk \
|
||||
findutils \
|
||||
brotli-dev \
|
||||
libgd \
|
||||
tar \
|
||||
xz \
|
||||
upx;
|
||||
|
||||
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 /;
|
||||
|
||||
RUN set -ex; \
|
||||
#build OpenSSL
|
||||
case "${APP_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 /; \
|
||||
;; \
|
||||
esac;
|
||||
|
||||
RUN set -ex; \
|
||||
# build brotli
|
||||
cd /; \
|
||||
git clone --recurse-submodules -j8 https://github.com/google/ngx_brotli; \
|
||||
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 -m64 -march=native -mtune=native -flto -funroll-loops -ffunction-sections -fdata-sections -Wl,--gc-sections" -DCMAKE_CXX_FLAGS="-Ofast -m64 -march=native -mtune=native -flto -funroll-loops -ffunction-sections -fdata-sections -Wl,--gc-sections" -DCMAKE_INSTALL_PREFIX=./installed ..; \
|
||||
cmake --build . --config Release --target brotlienc;
|
||||
|
||||
RUN set -ex; \
|
||||
#build QuickJS
|
||||
case "${APP_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 /; \
|
||||
cd ${BUILD_DEPENDENCY_QUICKJS_ROOT}; \
|
||||
CFLAGS='-fPIC -static -static-libgcc' make libquickjs.a; \
|
||||
;; \
|
||||
esac;
|
||||
|
||||
RUN set -ex; \
|
||||
#build XLST
|
||||
case "${APP_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 /; \
|
||||
cd /libxml2-2.14.1; \
|
||||
./configure \
|
||||
--prefix="/usr" \
|
||||
--disable-shared \
|
||||
--enable-static \
|
||||
--without-python; \
|
||||
make -s -j $(nproc); \
|
||||
make install; \
|
||||
cd /libxslt-1.1.43; \
|
||||
./configure \
|
||||
--prefix="/usr" \
|
||||
--disable-shared \
|
||||
--enable-static \
|
||||
--without-python; \
|
||||
make -s -j $(nproc); \
|
||||
make install; \
|
||||
;; \
|
||||
esac;
|
||||
|
||||
RUN set -ex; \
|
||||
case "${APP_NGINX_CONFIGURATION}" in \
|
||||
"light") \
|
||||
cd ${BUILD_ROOT}; \
|
||||
./configure \
|
||||
--with-zlib=${BUILD_DEPENDENCY_ZLIB_ROOT} \
|
||||
--with-pcre=${BUILD_DEPENDENCY_PCRE2_ROOT} \
|
||||
--add-module=${BUILD_DEPENDENCY_HEADERS_MORE_ROOT} \
|
||||
--add-module=${BUILD_DEPENDENCY_BROTLI_ROOT} \
|
||||
--prefix=${NGINX_PREFIX} \
|
||||
--sbin-path=${BUILD_BIN} \
|
||||
--modules-path=${APP_ROOT}/lib/modules \
|
||||
--conf-path=${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 \
|
||||
--lock-path=${APP_ROOT}/run/nginx.lock \
|
||||
--http-client-body-temp-path=${APP_ROOT}/cache/client_temp \
|
||||
--http-proxy-temp-path=${APP_ROOT}/cache/proxy_temp \
|
||||
--http-fastcgi-temp-path=${APP_ROOT}/cache/fastcgi_temp \
|
||||
--http-uwsgi-temp-path=${APP_ROOT}/cache/uwsgi_temp \
|
||||
--http-scgi-temp-path=${APP_ROOT}/cache/scgi_temp \
|
||||
--user=docker \
|
||||
--group=docker \
|
||||
--with-file-aio \
|
||||
--with-poll_module \
|
||||
--with-select_module \
|
||||
--with-http_addition_module \
|
||||
--with-http_dav_module \
|
||||
--with-http_flv_module \
|
||||
--with-http_gunzip_module \
|
||||
--with-http_gzip_static_module \
|
||||
--with-http_mp4_module \
|
||||
--with-http_realip_module \
|
||||
--with-http_stub_status_module \
|
||||
--with-http_sub_module \
|
||||
--with-http_v2_module \
|
||||
--without-http_autoindex_module \
|
||||
--without-http_browser_module \
|
||||
--without-http_charset_module \
|
||||
--without-http_empty_gif_module \
|
||||
--without-http_geo_module \
|
||||
--without-http_memcached_module \
|
||||
--without-http_map_module \
|
||||
--without-http_ssi_module \
|
||||
--without-http_split_clients_module \
|
||||
--without-http_fastcgi_module \
|
||||
--without-http_uwsgi_module \
|
||||
--without-http_userid_module \
|
||||
--without-http_scgi_module \
|
||||
--without-mail_pop3_module \
|
||||
--without-mail_imap_module \
|
||||
--without-mail_smtp_module \
|
||||
--with-cc-opt="-O2 -static -static-libgcc" \
|
||||
--with-ld-opt="-s -static"; \
|
||||
;; \
|
||||
"full") \
|
||||
cd ${BUILD_ROOT}; \
|
||||
./configure \
|
||||
--with-zlib=${BUILD_DEPENDENCY_ZLIB_ROOT} \
|
||||
--with-pcre=${BUILD_DEPENDENCY_PCRE2_ROOT} \
|
||||
--add-module=${BUILD_DEPENDENCY_HEADERS_MORE_ROOT} \
|
||||
--add-module=${BUILD_DEPENDENCY_BROTLI_ROOT} \
|
||||
--add-module=${BUILD_DEPENDENCY_NJS_ROOT}/nginx \
|
||||
--with-openssl=${BUILD_DEPENDENCY_OPENSSL_ROOT} \
|
||||
--prefix=${NGINX_PREFIX} \
|
||||
--sbin-path=${BUILD_BIN} \
|
||||
--modules-path=${APP_ROOT}/lib/modules \
|
||||
--conf-path=${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 \
|
||||
--lock-path=${APP_ROOT}/run/nginx.lock \
|
||||
--http-client-body-temp-path=${APP_ROOT}/cache/client_temp \
|
||||
--http-proxy-temp-path=${APP_ROOT}/cache/proxy_temp \
|
||||
--http-fastcgi-temp-path=${APP_ROOT}/cache/fastcgi_temp \
|
||||
--http-uwsgi-temp-path=${APP_ROOT}/cache/uwsgi_temp \
|
||||
--http-scgi-temp-path=${APP_ROOT}/cache/scgi_temp \
|
||||
--user=docker \
|
||||
--group=docker \
|
||||
--with-http_ssl_module \
|
||||
--with-http_realip_module \
|
||||
--with-http_addition_module \
|
||||
--with-http_sub_module \
|
||||
--with-http_dav_module \
|
||||
--with-http_flv_module \
|
||||
--with-http_mp4_module \
|
||||
--with-http_gunzip_module \
|
||||
--with-http_gzip_static_module \
|
||||
--with-http_random_index_module \
|
||||
--with-http_secure_link_module \
|
||||
--with-http_stub_status_module \
|
||||
--with-http_auth_request_module \
|
||||
--with-http_geoip_module \
|
||||
--with-threads \
|
||||
--with-stream \
|
||||
--with-stream_ssl_module \
|
||||
--with-stream_ssl_preread_module \
|
||||
--with-stream_realip_module \
|
||||
--with-stream_geoip_module \
|
||||
--with-http_slice_module \
|
||||
--with-http_xslt_module \
|
||||
--with-mail \
|
||||
--with-mail_ssl_module \
|
||||
--with-compat \
|
||||
--with-file-aio \
|
||||
--with-http_v2_module \
|
||||
--with-cc-opt="-O2 -static -static-libgcc -I ${BUILD_DEPENDENCY_QUICKJS_ROOT}" \
|
||||
--with-ld-opt="-s -static -L ${BUILD_DEPENDENCY_QUICKJS_ROOT}"; \
|
||||
;; \
|
||||
esac;
|
||||
|
||||
RUN set -ex; \
|
||||
cd ${BUILD_ROOT}; \
|
||||
make -s -j $(nproc); \
|
||||
eleven checkStatic ${BUILD_BIN};
|
||||
|
||||
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
|
||||
|
||||
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;
|
||||
|
||||
COPY ./rootfs/nginx ${APP_ROOT}
|
||||
|
||||
# :: Distroless / file system
|
||||
FROM scratch AS distroless-fs
|
||||
ARG APP_ROOT
|
||||
COPY --from=fs ${APP_ROOT} /${APP_ROOT}
|
||||
|
||||
|
||||
# :: Header
|
||||
FROM 11notes/alpine:stable
|
||||
FROM 11notes/distroless AS distroless
|
||||
FROM 11notes/distroless:curl AS distroless-curl
|
||||
FROM scratch
|
||||
|
||||
# :: arguments
|
||||
ARG TARGETARCH
|
||||
@@ -111,50 +308,18 @@
|
||||
ENV APP_VERSION=${APP_VERSION}
|
||||
ENV APP_ROOT=${APP_ROOT}
|
||||
|
||||
ENV NGINX_HEALTHCHECK_URL="https://localhost:8443/ping"
|
||||
|
||||
# :: multi-stage
|
||||
COPY --from=util /usr/local/bin/ /usr/local/bin
|
||||
COPY --from=build /usr/sbin/nginx /usr/sbin
|
||||
COPY --from=build /etc/nginx/ /etc/nginx
|
||||
COPY --from=build /usr/lib/nginx/modules/ /etc/nginx/modules
|
||||
|
||||
# :: Run
|
||||
USER root
|
||||
RUN eleven printenv;
|
||||
|
||||
# :: install application
|
||||
RUN set -ex; \
|
||||
apk --no-cache --update add \
|
||||
inotify-tools \
|
||||
openssl \
|
||||
pcre2-dev;
|
||||
|
||||
RUN set -ex; \
|
||||
eleven mkdir ${APP_ROOT}/{etc,var,ssl,cache,run}; \
|
||||
mkdir -p /var/log/nginx; \
|
||||
touch /var/log/nginx/access.log; \
|
||||
touch /var/log/nginx/error.log; \
|
||||
ln -sf /dev/stdout /var/log/nginx/access.log; \
|
||||
ln -sf /dev/stderr /var/log/nginx/error.log;
|
||||
|
||||
# :: copy filesystem changes and set correct permissions
|
||||
COPY ./rootfs /
|
||||
RUN set -ex; \
|
||||
chmod +x -R /usr/local/bin; \
|
||||
chown -R 1000:1000 \
|
||||
${APP_ROOT} \
|
||||
/var/log/nginx;
|
||||
|
||||
# :: support unraid
|
||||
RUN set -ex; \
|
||||
eleven unraid;
|
||||
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} / /
|
||||
|
||||
# :: Volumes
|
||||
VOLUME ["${APP_ROOT}/etc", "${APP_ROOT}/var"]
|
||||
|
||||
# :: Monitor
|
||||
HEALTHCHECK --interval=5s --timeout=2s CMD curl -X GET -kILs --fail ${NGINX_HEALTHCHECK_URL} || exit 1
|
||||
HEALTHCHECK --interval=5s --timeout=2s CMD ["/usr/local/bin/curl", "-kILs", "--fail", "http://localhost:3000/ping"]
|
||||
|
||||
# :: Start
|
||||
USER docker
|
||||
USER ${APP_UID}:${APP_GID}
|
||||
ENTRYPOINT ["/usr/local/bin/nginx"]
|
18
compose.yaml
18
compose.yaml
@@ -1,17 +1,25 @@
|
||||
name: "nginx"
|
||||
services:
|
||||
nginx:
|
||||
image: "11notes/nginx:1.26.2"
|
||||
container_name: "nginx"
|
||||
image: "11notes/nginx:1.26.3"
|
||||
read_only: true
|
||||
environment:
|
||||
TZ: "Europe/Zurich"
|
||||
ports:
|
||||
- "8443:8443/tcp"
|
||||
- "3000:3000/tcp"
|
||||
networks:
|
||||
frontend:
|
||||
volumes:
|
||||
- "etc:/nginx/etc"
|
||||
- "var:/nginx/var"
|
||||
- "ssl:/nginx/ssl"
|
||||
tmpfs:
|
||||
- "/nginx/cache:uid=1000,gid=1000"
|
||||
- "/nginx/run:uid=1000,gid=1000"
|
||||
restart: "always"
|
||||
|
||||
volumes:
|
||||
etc:
|
||||
var:
|
||||
ssl:
|
||||
|
||||
networks:
|
||||
frontend:
|
25
project.md
25
project.md
@@ -1,7 +1,26 @@
|
||||
${{ content_synopsis }} What can I do with this? This image will serve as a base for nginx related images that need a high-performance webserver. It can also be used stand alone as a webserver or reverse proxy. It will automatically reload on config changes if configured.
|
||||
${{ 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 don’t do or offer these options:
|
||||
|
||||
${{ 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
|
||||
|
||||
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.
|
||||
|
||||
${{ title_config }}
|
||||
```yaml
|
||||
${{ include: ./rootfs/etc/nginx/nginx.conf }}
|
||||
```
|
||||
|
||||
The default configuration contains no special settings. It enables brotli compression, sets the workers to the same amount as n-CPUs available, has two default logging formats, disables most stuff not needed and enables best performance settings. Please mount your own config if you need to change how nginx is setup.
|
||||
|
||||
${{ title_volumes }}
|
||||
* **${{ json_root }}/etc** - Directory of vHost config, must end in *.conf (set in /etc/nginx/nginx.conf)
|
||||
* **${{ json_root }}/etc** - Directory of vHost config, must end in *.conf
|
||||
* **${{ json_root }}/var** - Directory of webroot for vHost
|
||||
|
||||
${{ content_compose }}
|
||||
@@ -9,8 +28,6 @@ ${{ content_compose }}
|
||||
${{ content_defaults }}
|
||||
|
||||
${{ content_environment }}
|
||||
| `NGINX_DYNAMIC_RELOAD` | Enable reload of nginx on configuration changes in /nginx/etc (only on successful configuration test!) | |
|
||||
| `NGINX_HEALTHCHECK_URL` | URL to check if nginx is ready to accept connections | https://localhost:8443/ping |
|
||||
|
||||
${{ content_source }}
|
||||
|
||||
|
@@ -1,7 +1,8 @@
|
||||
worker_processes auto;
|
||||
worker_cpu_affinity auto;
|
||||
worker_rlimit_nofile 204800;
|
||||
error_log /var/log/nginx/error.log warn;
|
||||
error_log /nginx/log/error.log warn;
|
||||
daemon off;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
@@ -25,6 +26,36 @@ http {
|
||||
tcp_nodelay on;
|
||||
gzip on;
|
||||
|
||||
brotli on;
|
||||
brotli_comp_level 4;
|
||||
brotli_static on;
|
||||
brotli_types
|
||||
text/plain
|
||||
text/css
|
||||
text/xml
|
||||
text/javascript
|
||||
text/x-component
|
||||
application/xml
|
||||
application/xml+rss
|
||||
application/javascript
|
||||
application/json
|
||||
application/atom+xml
|
||||
application/vnd.ms-fontobject
|
||||
application/x-font-ttf
|
||||
application/x-font-opentype
|
||||
application/x-font-truetype
|
||||
application/x-web-app-manifest+json
|
||||
application/xhtml+xml
|
||||
application/octet-stream
|
||||
font/opentype
|
||||
font/truetype
|
||||
font/eot
|
||||
font/otf
|
||||
image/svg+xml
|
||||
image/x-icon
|
||||
image/vnd.microsoft.icon
|
||||
image/bmp;
|
||||
|
||||
client_max_body_size 8M;
|
||||
keepalive_timeout 90;
|
||||
keepalive_requests 102400;
|
||||
@@ -37,5 +68,7 @@ http {
|
||||
open_file_cache_min_uses 2;
|
||||
open_file_cache_errors off;
|
||||
|
||||
root /nginx/var;
|
||||
|
||||
include /nginx/etc/*.conf;
|
||||
}
|
@@ -1,9 +1,10 @@
|
||||
server {
|
||||
listen 8443 default_server ssl;
|
||||
listen 3000 default_server;
|
||||
server_name _;
|
||||
|
||||
ssl_certificate /nginx/ssl/default.crt;
|
||||
ssl_certificate_key /nginx/ssl/default.key;
|
||||
location / {
|
||||
return 404;
|
||||
}
|
||||
|
||||
location /ping {
|
||||
return 200;
|
||||
|
@@ -1,22 +0,0 @@
|
||||
#!/bin/ash
|
||||
if { [ ! -f "${APP_ROOT}/ssl/default.crt" ] && [ -f "${APP_ROOT}/etc/default.conf" ] && cat ${APP_ROOT}/etc/default.conf | grep -q "default.crt"; }; then
|
||||
eleven log debug "creating default certificate"
|
||||
openssl req -x509 -newkey rsa:4096 -subj "/C=XX/ST=XX/L=XX/O=XX/OU=DOCKER/CN=${APP_NAME}" \
|
||||
-keyout "${APP_ROOT}/ssl/default.key" \
|
||||
-out "${APP_ROOT}/ssl/default.crt" \
|
||||
-days 3650 -nodes -sha256 &> /dev/null
|
||||
fi
|
||||
|
||||
if [ -z "${1}" ]; then
|
||||
if [ ! -z ${NGINX_DYNAMIC_RELOAD} ]; then
|
||||
eleven log info "enable dynamic reload"
|
||||
/sbin/inotifyd /usr/local/bin/reload.sh ${APP_ROOT}/etc:cdnym &
|
||||
fi
|
||||
|
||||
set -- "nginx" \
|
||||
-g \
|
||||
'daemon off;'
|
||||
eleven log start
|
||||
fi
|
||||
|
||||
exec "$@"
|
@@ -1,26 +0,0 @@
|
||||
#!/bin/ash
|
||||
eleven log debug "inotifyd event: ${1}"
|
||||
eleven log info "reloading config"
|
||||
NGINX_DYNAMIC_RELOAD_LOG=${APP_ROOT}/run/reload.log
|
||||
nginx -t &> ${NGINX_DYNAMIC_RELOAD_LOG}
|
||||
|
||||
while read -r LINE; do
|
||||
if echo "${LINE}" | grep -q "nginx: "; then
|
||||
if echo "${LINE}" | grep -q "\[warn\]"; then
|
||||
LINE=$(echo ${LINE} | sed 's/nginx: \[warn\] //')
|
||||
eleven log warning "${LINE}"
|
||||
fi
|
||||
|
||||
if echo "${LINE}" | grep -q "\[emerg\]"; then
|
||||
LINE=$(echo ${LINE} | sed 's/nginx: \[emerg\] //')
|
||||
eleven log error "${LINE}"
|
||||
fi
|
||||
fi
|
||||
done < ${NGINX_DYNAMIC_RELOAD_LOG}
|
||||
|
||||
if cat ${NGINX_DYNAMIC_RELOAD_LOG} | grep -q "test is successful"; then
|
||||
nginx -s reload
|
||||
eleven log info "config reloaded"
|
||||
else
|
||||
eleven log error "config reload failed!"
|
||||
fi
|
Reference in New Issue
Block a user