make image smaller + allow long passwd + dep updates + fix compression/misspellings

Signed-off-by: Zoey <zoey@z0ey.de>
This commit is contained in:
Zoey
2023-02-09 12:10:24 +01:00
parent 45895ac53e
commit 14c2253721
28 changed files with 162 additions and 187 deletions

View File

@@ -1,35 +1,27 @@
name: Docker push develop to latest name: Docker push develop to latest
on: on:
workflow_dispatch: workflow_dispatch:
jobs: jobs:
docker: docker:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout
uses: actions/checkout@v3
- name: Login to DockerHub - name: Login to DockerHub
if: github.event_name != 'pull_request' if: github.event_name != 'pull_request'
uses: docker/login-action@v2 uses: docker/login-action@v2
with: with:
username: ${{ secrets.DOCKER_USERNAME }} username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }} password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login to GitHub Container Registry - name: Login to GitHub Container Registry
uses: docker/login-action@v2 uses: docker/login-action@v2
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ secrets.DOCKER_USERNAME }} username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ github.token }} password: ${{ github.token }}
- name: Push develop to latest - name: Push develop to latest
run: | run: |
docker buildx imagetools create --tag ${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:latest ${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:${{ github.ref_name }} docker buildx imagetools create --tag ${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:latest ${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:${{ github.ref_name }}
docker buildx imagetools create --tag ghcr.io/${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:latest ghcr.io/${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:${{ github.ref_name }} docker buildx imagetools create --tag ghcr.io/${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:latest ghcr.io/${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:${{ github.ref_name }}
- name: Show Nginx version - name: Show Nginx version
run: | run: |
docker run --rm --entrypoint nginx ${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:latest -V docker run --rm --entrypoint nginx ${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:latest -V
docker run --rm --entrypoint nginx ghcr.io/${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:latest -V docker run --rm --entrypoint nginx ghcr.io/${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:latest -V

View File

@@ -1,12 +1,11 @@
name: Build Docker Image name: Build Docker Image
on: on:
workflow_run: workflow_run:
workflows: ["Build frontend"] workflows: ["Build frontend"]
types: types:
- completed - completed
push: push:
branches: branches:
- develop - develop
paths: paths:
- .github/workflows/docker.yml - .github/workflows/docker.yml
@@ -14,84 +13,68 @@ on:
- backend/** - backend/**
- rootfs/** - rootfs/**
workflow_dispatch: workflow_dispatch:
jobs: jobs:
backend-test: backend-test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 18
- name: Test Backend - name: Test Backend
run: | run: |
sudo npm install --global cross-env sudo pip install certbot
sudo pip install certbot sudo mkdir -p /usr/local/nginx/conf/conf.d/include /data/tls/certbot /tmp/acme-challenge
sudo mkdir -p /usr/local/nginx/conf/conf.d/include /data/tls/certbot /tmp/acme-challenge sudo touch /usr/local/nginx/conf/conf.d/include/ip_ranges.conf
sudo touch /usr/local/nginx/conf/conf.d/include/ip_ranges.conf sudo cp rootfs/etc/tls/certbot.ini /data/tls/certbot/config.ini
sudo cp rootfs/etc/tls/certbot.ini /data/tls/certbot/config.ini mv global backend
mv global backend cd backend
cd backend npm install --force
npm install --force sudo nginx
sudo nginx NODE_ENV=production sudo -E timeout 30 node --abort_on_uncaught_exception --max_old_space_size=250 index.js || if [ "$?" == "124" ]; then exit 0; else exit 1; fi
cross-env NODE_ENV=production sudo -E timeout 30 node --abort_on_uncaught_exception --max_old_space_size=250 index.js || if [ "$?" == "124" ]; then exit 0; else exit 1; fi
- name: Kill workflow - name: Kill workflow
if: failure() if: failure()
run: | run: |
curl -X POST https://api.github.com/repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/cancel --header "authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" curl -X POST https://api.github.com/repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/cancel --header "authorization: Bearer ${{ secrets.GITHUB_TOKEN }}"
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: Load frontend from cache - name: Load frontend from cache
uses: actions/cache/restore@v3 uses: actions/cache/restore@v3
with: with:
path: frontend/dist path: frontend/dist
key: frontend key: frontend
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v2 uses: docker/setup-qemu-action@v2
with: with:
platforms: arm64 #all platforms: arm64 #all
- name: Set up Docker Buildx - name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v2 uses: docker/setup-buildx-action@v2
with: with:
driver-opts: env.BUILDKIT_STEP_LOG_MAX_SIZE=-1 driver-opts: env.BUILDKIT_STEP_LOG_MAX_SIZE=-1
- name: Login to DockerHub - name: Login to DockerHub
uses: docker/login-action@v2 uses: docker/login-action@v2
with: with:
username: ${{ secrets.DOCKER_USERNAME }} username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }} password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login to GitHub Container Registry - name: Login to GitHub Container Registry
uses: docker/login-action@v2 uses: docker/login-action@v2
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ secrets.DOCKER_USERNAME }} username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ github.token }} password: ${{ github.token }}
- name: Build - name: Build
uses: docker/build-push-action@v3 uses: docker/build-push-action@v4
with: with:
context: . context: .
file: ./Dockerfile file: ./Dockerfile
platforms: linux/amd64,linux/arm64 #,linux/amd64/v2,linux/amd64/v3,linux/amd64/v4 #,linux/ppc64le,linux/s390x,linux/386,linux/arm/v7,linux/arm/v6 platforms: linux/amd64,linux/arm64 #,linux/amd64/v2,linux/amd64/v3,linux/amd64/v4 #,linux/ppc64le,linux/s390x,linux/386,linux/arm/v7,linux/arm/v6
push: ${{ github.ref == 'refs/heads/develop' }} push: ${{ github.ref == 'refs/heads/develop' }}
tags: | tags: "ghcr.io/${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:${{ github.ref_name }}\n${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:${{ github.ref_name }}\n \n"
ghcr.io/${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:${{ github.ref_name }}
${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:${{ github.ref_name }}
- name: show version - name: show version
run: | run: |
docker run --rm --entrypoint nginx ${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:${{ github.ref_name }} -V docker run --rm --entrypoint nginx ${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:${{ github.ref_name }} -V
docker run --rm --entrypoint nginx ghcr.io/${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:${{ github.ref_name }} -V docker run --rm --entrypoint nginx ghcr.io/${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:${{ github.ref_name }} -V

View File

@@ -1,38 +1,33 @@
name: Build frontend name: Build frontend
on: on:
push: push:
branches: branches:
- develop - develop
paths: paths:
- .github/workflows/frontend.yml - .github/workflows/frontend.yml
- frontend/** - frontend/**
- global/** - global/**
workflow_dispatch: workflow_dispatch:
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 18
- name: Prepare frontend
- name: Prepair frontend
run: | run: |
curl https://api.github.com/repos/${{ github.repository }}/actions/caches?key=frontend -X DELETE --header "authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" export NODE_OPTIONS=--openssl-legacy-provider
export NODE_OPTIONS=--openssl-legacy-provider npm install --global yarn
npm install --global yarn cd frontend
cd frontend sed -i "s|\"0.0.0\"|\""$(cat ../global/.version)"\"|g" package.json
sed -i "s|\"0.0.0\"|\""$(cat ../global/.version)"\"|g" package.json yarn --no-lockfile install
yarn --no-lockfile install yarn --no-lockfile build
yarn --no-lockfile build mkdir dist/.well-known
mkdir dist/.well-known cp ../security.txt dist/.well-known
cp ../security.txt dist/.well-known curl https://api.github.com/repos/${{ github.repository }}/actions/caches?key=frontend -X DELETE --header "authorization: Bearer ${{ secrets.GITHUB_TOKEN }}"
- name: Cache frontend - name: Cache frontend
uses: actions/cache/save@v3 uses: actions/cache/save@v3
with: with:

View File

@@ -1,10 +1,8 @@
name: JSON check name: JSON check
on: on:
push: push:
pull_request: pull_request:
workflow_dispatch: workflow_dispatch:
jobs: jobs:
test-json: test-json:
runs-on: ubuntu-latest runs-on: ubuntu-latest

View File

@@ -1,5 +1,4 @@
name: Build PR name: Build PR
on: on:
pull_request: pull_request:
paths: paths:
@@ -9,91 +8,75 @@ on:
- backend/** - backend/**
- global/** - global/**
- rootfs/** - rootfs/**
jobs: jobs:
backend-test: backend-test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 18
- name: Test Backend - name: Test Backend
run: | run: |
sudo npm install --global cross-env sudo pip install certbot
sudo pip install certbot sudo mkdir -p /usr/local/nginx/conf/conf.d/include /data/tls/certbot /tmp/acme-challenge
sudo mkdir -p /usr/local/nginx/conf/conf.d/include /data/tls/certbot /tmp/acme-challenge sudo touch /usr/local/nginx/conf/conf.d/include/ip_ranges.conf
sudo touch /usr/local/nginx/conf/conf.d/include/ip_ranges.conf sudo cp rootfs/etc/tls/certbot.ini /data/tls/certbot/config.ini
sudo cp rootfs/etc/tls/certbot.ini /data/tls/certbot/config.ini mv global backend
mv global backend cd backend
cd backend npm install --force
npm install --force sudo nginx
sudo nginx NODE_ENV=production sudo -E timeout 30 node --abort_on_uncaught_exception --max_old_space_size=250 index.js || if [ "$?" == "124" ]; then exit 0; else exit 1; fi
cross-env NODE_ENV=production sudo -E timeout 30 node --abort_on_uncaught_exception --max_old_space_size=250 index.js || if [ "$?" == "124" ]; then exit 0; else exit 1; fi
- name: Kill workflow - name: Kill workflow
if: failure() if: failure()
run: | run: |
curl -X POST https://api.github.com/repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/cancel --header "authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" curl -X POST https://api.github.com/repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/cancel --header "authorization: Bearer ${{ secrets.GITHUB_TOKEN }}"
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 18
- name: Prepare frontend
- name: Prepair frontend
run: | run: |
export NODE_OPTIONS=--openssl-legacy-provider export NODE_OPTIONS=--openssl-legacy-provider
npm install --global yarn npm install --global yarn
cd frontend cd frontend
sed -i "s|\"0.0.0\"|\""$(cat ../global/.version)"\"|g" package.json sed -i "s|\"0.0.0\"|\""$(cat ../global/.version)"\"|g" package.json
yarn --no-lockfile install yarn --no-lockfile install
yarn --no-lockfile build yarn --no-lockfile build
mkdir dist/.well-known mkdir dist/.well-known
cp ../security.txt dist/.well-known cp ../security.txt dist/.well-known
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v2 uses: docker/setup-qemu-action@v2
with: with:
platforms: arm64 #all platforms: arm64 #all
- name: Set up Docker Buildx - name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v2 uses: docker/setup-buildx-action@v2
with: with:
driver-opts: env.BUILDKIT_STEP_LOG_MAX_SIZE=-1 driver-opts: env.BUILDKIT_STEP_LOG_MAX_SIZE=-1
- name: Login to GitHub Container Registry - name: Login to GitHub Container Registry
uses: docker/login-action@v2 uses: docker/login-action@v2
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ secrets.DOCKER_USERNAME }} username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ github.token }} password: ${{ github.token }}
- name: Set PR-Number - name: Set PR-Number
id: pr id: pr
run: echo "pr=$(echo pr-${{ github.ref_name }} | sed "s/refs\/pull\/://g" | sed "s/\/merge//g")" >> $GITHUB_OUTPUT run: echo "pr=$(echo pr-${{ github.ref_name }} | sed "s|refs/pull/:||g" | sed "s|/merge||g")" >> $GITHUB_OUTPUT
- name: Build - name: Build
uses: docker/build-push-action@v3 uses: docker/build-push-action@v4
with: with:
context: . context: .
file: ./Dockerfile file: ./Dockerfile
platforms: linux/amd64,linux/arm64 #,linux/amd64/v2,linux/amd64/v3,linux/amd64/v4 #,linux/ppc64le,linux/s390x,linux/386,linux/arm/v7,linux/arm/v6 platforms: linux/amd64,linux/arm64 #,linux/amd64/v2,linux/amd64/v3,linux/amd64/v4 #,linux/ppc64le,linux/s390x,linux/386,linux/arm/v7,linux/arm/v6
push: ${{ github.event_name == 'pull_request' }} push: ${{ github.event_name == 'pull_request' }}
tags: ghcr.io/${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:${{ steps.pr.outputs.pr }} tags: ghcr.io/${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:${{ steps.pr.outputs.pr }}
- name: show version - name: show version
run: docker run --rm --entrypoint nginx ghcr.io/${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:${{ steps.pr.outputs.pr }} -V run: docker run --rm --entrypoint nginx ghcr.io/${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:${{ steps.pr.outputs.pr }} -V
- name: add comment - name: add comment
uses: mshick/add-pr-comment@v2 uses: mshick/add-pr-comment@v2
with: with:

View File

@@ -1,19 +1,17 @@
name: Shellcheck name: Shellcheck
on: on:
push: push:
pull_request: pull_request:
workflow_dispatch: workflow_dispatch:
jobs: jobs:
shellcheck: shellcheck:
name: Check Shell name: Check Shell
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Run Shellcheck - name: Run Shellcheck
uses: ludeeus/action-shellcheck@master uses: ludeeus/action-shellcheck@master
with: with:
check_together: 'yes' check_together: 'yes'
env: env:
SHELLCHECK_OPTS: --shell sh SHELLCHECK_OPTS: --shell sh

View File

@@ -11,4 +11,4 @@ jobs:
uses: reviewdog/action-misspell@v1 uses: reviewdog/action-misspell@v1
with: with:
github_token: ${{ secrets.github_token }} github_token: ${{ secrets.github_token }}
locale: "US" locale: "US"

20
.github/workflows/yq.yml vendored Normal file
View File

@@ -0,0 +1,20 @@
name: yq
on:
workflow_dispatch:
jobs:
yq:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
token: ${{ secrets.YQ }}
- name: update workflows
run: for workflow in .github/workflows/*.yml; do yq "$workflow" | tee "$workflow".tmp && mv "$workflow".tmp "$workflow"; done
- name: push changes
run: |
git config user.name "GitHub"
git config user.email "noreply@github.com"
git add -A
git diff-index --quiet HEAD || git commit -sm "yq"
git push

View File

@@ -1,4 +1,4 @@
FROM zoeyvid/nginx-quic:51 FROM zoeyvid/nginx-quic:81
COPY rootfs / COPY rootfs /
COPY backend /app COPY backend /app
COPY global /app/global COPY global /app/global
@@ -6,27 +6,21 @@ COPY frontend/dist /app/frontend
WORKDIR /app WORKDIR /app
RUN apk upgrade --no-cache && \ RUN apk upgrade --no-cache && \
apk add --no-cache ca-certificates wget tzdata \ apk add --no-cache ca-certificates tzdata \
python3 nodejs-current npm \ nodejs-current \
gcc g++ libffi-dev python3-dev \ openssl apache2-utils \
grep coreutils jq openssl apache2-utils && \ coreutils grep jq curl \
# Install cross-env npm build-base libffi-dev && \
npm install --global cross-env && \
# Install pip
wget https://bootstrap.pypa.io/get-pip.py -O - | python3 && \
# Change permission
chmod +x /bin/start.sh && \
chmod +x /bin/check-health.sh && \
# Build Backend # Build Backend
sed -i "s|\"0.0.0\"|\""$(cat global/.version)"\"|g" package.json && \ sed -i "s|\"0.0.0\"|\""$(cat global/.version)"\"|g" package.json && \
npm install --force && \ npm install --force && \
# Install Certbot # Install Certbot
pip install --no-cache-dir certbot && \ pip install --no-cache-dir certbot && \
# Clean # Clean
apk del --no-cache npm gcc g++ libffi-dev python3-dev apk del --no-cache npm build-base libffi-dev
ENV NODE_ENV=production \ ENV NODE_ENV=production \
DB_SQLITE_FILE=/data/database.sqlite DB_SQLITE_FILE=/data/database.sqlite
ENTRYPOINT ["start.sh"] ENTRYPOINT ["start.sh"]
HEALTHCHECK CMD check-health.sh HEALTHCHECK CMD check-health.sh

View File

@@ -53,9 +53,9 @@ so that the barrier for entry here is low.
- Easy security headers, see [here](https://github.com/GetPageSpeed/ngx_security_headers) - Easy security headers, see [here](https://github.com/GetPageSpeed/ngx_security_headers)
- Access Log disabled - Access Log disabled
- Error Log written to console - Error Log written to console
- PHP optinal, you can add php extensions, see aviable packages [here](https://pkgs.alpinelinux.org/packages?branch=edge&repo=community&arch=x86_64&name=php81-*) and [here](https://pkgs.alpinelinux.org/packages?branch=edge&repo=community&arch=x86_64&name=php82-*) - PHP optinal, you can add php extensions, see aviable packages [here](https://pkgs.alpinelinux.org/packages?branch=v3.17&repo=community&arch=x86_64&name=php81-*) and [here](https://pkgs.alpinelinux.org/packages?branch=v3.17&repo=community&arch=x86_64&name=php82-*)
- allows different acme servers - allows different acme servers
- up to 64 domains per cert allowed - up to 99 domains per cert allowed
- Brotli can be enabled - Brotli can be enabled
- HTTP/2 always enabled - HTTP/2 always enabled
- HTTP/2 upload fixed - HTTP/2 upload fixed
@@ -72,9 +72,9 @@ so that the barrier for entry here is low.
# Use as webserver # Use as webserver
1. Create a new Proxy Host 1. Create a new Proxy Host
2. Set `Scheme` to `http`, `Forward Hostname / IP` to `0.0.0.0`, `Forward Port` to `1` and enable `Websockets Support` (you can also use other values, since these get fully ignored) 2. Set `Scheme` to `https`, `Forward Hostname / IP` to `0.0.0.0`, `Forward Port` to `1` and enable `Websockets Support` (you can also use other values, since these get fully ignored)
3. Maybe set an Access List 3. Maybe set an Access List
4. Make your SSL Settings 4. Make your TLS Settings
5. 5.
a) Custom Nginx Configuration (advanced tab), which looks the following for file server: a) Custom Nginx Configuration (advanced tab), which looks the following for file server:
- Note: the slash at the end of the file path is important - Note: the slash at the end of the file path is important
@@ -87,7 +87,7 @@ b) Custom Nginx Configuration (advanced tab), which looks the following for file
- Note: the slash at the end of the file path is important - Note: the slash at the end of the file path is important
- Note: first enable `PHP81` and/or `PHP82` inside your compose file - Note: first enable `PHP81` and/or `PHP82` inside your compose file
- Note: you can replace `fastcgi_pass php82;` with `fastcgi_pass` `php81`/`php82` `;` - Note: you can replace `fastcgi_pass php82;` with `fastcgi_pass` `php81`/`php82` `;`
- Note: to add more php extension use the packes from [here](https://pkgs.alpinelinux.org/packages?branch=edge&repo=community&arch=x86_64&name=php8*-*) and add them using the `PHP_APKS` env (see compose file) - Note: to add more php extension use the packes from [here](https://pkgs.alpinelinux.org/packages?branch=v3.17&repo=community&arch=x86_64&name=php8*-*) and add them using the `PHP_APKS` env (see compose file)
``` ```
location / { location / {
alias /var/www/<your-php-site-folder-name>/; alias /var/www/<your-php-site-folder-name>/;
@@ -134,9 +134,9 @@ services:
# - "CLEAN=false" # Clean folders # - "CLEAN=false" # Clean folders
# - "FULLCLEAN=true" # Clean unused config folders # - "FULLCLEAN=true" # Clean unused config folders
# - "PHP81=true" # Activate PHP81 # - "PHP81=true" # Activate PHP81
# - "PHP81_APKS=php81-curl php-81-curl" # Add php extensions, see aviable packages here: https://pkgs.alpinelinux.org/packages?branch=edge&repo=community&arch=x86_64&name=php81-* # - "PHP81_APKS=php81-curl php-81-curl" # Add php extensions, see aviable packages here: https://pkgs.alpinelinux.org/packages?branch=v3.17&repo=community&arch=x86_64&name=php81-*
# - "PHP82=true" # Activate PHP82 # - "PHP82=true" # Activate PHP82
# - "PHP82_APKS=php82-curl php-82-curl" # Add php extensions, see aviable packages here: https://pkgs.alpinelinux.org/packages?branch=edge&repo=community&arch=x86_64&name=php82-* # - "PHP82_APKS=php82-curl php-82-curl" # Add php extensions, see aviable packages here: https://pkgs.alpinelinux.org/packages?branch=v3.17&repo=community&arch=x86_64&name=php82-*
``` ```
3. Bring up your stack by running (or deploy your portainer stack) 3. Bring up your stack by running (or deploy your portainer stack)
@@ -149,14 +149,14 @@ docker compose up -d
When your docker container is running, connect to it on port `81` for the admin interface. When your docker container is running, connect to it on port `81` for the admin interface.
Sometimes this can take a little bit because of the entropy of keys. Sometimes this can take a little bit because of the entropy of keys.
You may need to open port 81 in your firewall. You may need to open port 81 in your firewall.
You may need to use another IP-Adress. You may need to use another IP-Address.
[https://127.0.0.1:81](https://127.0.0.1:81) [https://127.0.0.1:81](https://127.0.0.1:81)
Default Admin User: Default Admin User:
``` ```
Email: admin@example.com Email: admin@example.com
Password: 9KcvfmAvcVonB7YOMqdjJGsTG2JL058Rx6xFNMintAeaGETsRBRlSbfXdi1inoCa Password: iArhP1j7p1P6TA92FA2FMbbUGYqwcYzxC4AVEe12Wbi94FY9gNN62aKyF1shrvG4NycjjX9KfmDQiwkLZH1ZDR9xMjiG2QmoHXi
``` ```
Immediately after logging in with this default user you will be asked to modify your details and change your password. Immediately after logging in with this default user you will be asked to modify your details and change your password.

View File

@@ -1150,14 +1150,14 @@
"current": { "current": {
"type": "string", "type": "string",
"minLength": 1, "minLength": 1,
"maxLength": 64, "maxLength": 99,
"example": "9KcvfmAvcVonB7YOMqdjJGsTG2JL058Rx6xFNMintAeaGETsRBRlSbfXdi1inoCa" "example": "iArhP1j7p1P6TA92FA2FMbbUGYqwcYzxC4AVEe12Wbi94FY9gNN62aKyF1shrvG4NycjjX9KfmDQiwkLZH1ZDR9xMjiG2QmoHXi"
}, },
"secret": { "secret": {
"type": "string", "type": "string",
"minLength": 8, "minLength": 8,
"maxLength": 64, "maxLength": 99,
"example": "mySuperN3wP@ssword!" "example": "5wdvvveVKkNNr8K7fSQKoUWbYyCZ2abtLaa1J5LzAvMfkGVcGBXHQ32iuPdeKdNfQVZiPKee3ZPKaGMvFR5t94QCeZbK3faSVYu"
} }
} }
}, },
@@ -1251,4 +1251,4 @@
} }
} }
} }
} }

View File

@@ -21,7 +21,7 @@ const permsSchema = require('./access/permissions.json');
module.exports = function (token_string) { module.exports = function (token_string) {
let Token = new TokenModel(); let Token = new TokenModel();
let token_data = null; let token_data = null;
let initialised = false; let initialized = false;
let object_cache = {}; let object_cache = {};
let allow_internal_access = false; let allow_internal_access = false;
let user_roles = []; let user_roles = [];
@@ -34,7 +34,7 @@ module.exports = function (token_string) {
*/ */
this.init = () => { this.init = () => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (initialised) { if (initialized) {
resolve(); resolve();
} else if (!token_string) { } else if (!token_string) {
reject(new error.PermissionError('Permission Denied')); reject(new error.PermissionError('Permission Denied'));
@@ -74,7 +74,7 @@ module.exports = function (token_string) {
if (!is_ok) { if (!is_ok) {
throw new error.AuthError('Invalid token scope for User'); throw new error.AuthError('Invalid token scope for User');
} else { } else {
initialised = true; initialized = true;
user_roles = user.roles; user_roles = user.roles;
permissions = user.permissions; permissions = user.permissions;
} }
@@ -84,7 +84,7 @@ module.exports = function (token_string) {
} }
}); });
} else { } else {
initialised = true; initialized = true;
} }
})); }));
} }
@@ -248,7 +248,7 @@ module.exports = function (token_string) {
} else { } else {
return this.init() return this.init()
.then(() => { .then(() => {
// Initialised, token decoded ok // initialized, token decoded ok
return this.getObjectSchema(permission) return this.getObjectSchema(permission)
.then((objectSchema) => { .then((objectSchema) => {
let data_schema = { let data_schema = {

View File

@@ -4,12 +4,12 @@
"description": "A beautiful interface for creating Nginx endpoints", "description": "A beautiful interface for creating Nginx endpoints",
"main": "js/index.js", "main": "js/index.js",
"dependencies": { "dependencies": {
"@apidevtools/json-schema-ref-parser": "10.0.1", "@apidevtools/json-schema-ref-parser": "10.1.0",
"ajv": "6.12.6", "ajv": "6.12.6",
"archiver": "5.3.1", "archiver": "5.3.1",
"batchflow": "0.4.0", "batchflow": "0.4.0",
"bcrypt": "5.1.0", "bcrypt": "5.1.0",
"body-parser": "1.20.1", "body-parser": "1.20.2",
"compression": "1.7.4", "compression": "1.7.4",
"config": "3.3.9", "config": "3.3.9",
"express": "4.18.2", "express": "4.18.2",

View File

@@ -172,7 +172,7 @@
"description": "Domain Names separated by a comma", "description": "Domain Names separated by a comma",
"example": "*.jc21.com,blog.jc21.com", "example": "*.jc21.com,blog.jc21.com",
"type": "array", "type": "array",
"maxItems": 64, "maxItems": 99,
"uniqueItems": true, "uniqueItems": true,
"items": { "items": {
"type": "string", "type": "string",

View File

@@ -194,12 +194,12 @@
"current": { "current": {
"type": "string", "type": "string",
"minLength": 1, "minLength": 1,
"maxLength": 64 "maxLength": 99
}, },
"secret": { "secret": {
"type": "string", "type": "string",
"minLength": 8, "minLength": 8,
"maxLength": 64 "maxLength": 99
} }
} }
}, },

View File

@@ -80,7 +80,7 @@ const setupDefaultUser = () => {
.then((row) => { .then((row) => {
if (!row.count) { if (!row.count) {
// Create a new user and set password // Create a new user and set password
logger.info('Creating a new user: admin@example.com with password: 9KcvfmAvcVonB7YOMqdjJGsTG2JL058Rx6xFNMintAeaGETsRBRlSbfXdi1inoCa'); logger.info('Creating a new user: admin@example.com with password: iArhP1j7p1P6TA92FA2FMbbUGYqwcYzxC4AVEe12Wbi94FY9gNN62aKyF1shrvG4NycjjX9KfmDQiwkLZH1ZDR9xMjiG2QmoHXi');
let data = { let data = {
is_deleted: 0, is_deleted: 0,
@@ -100,7 +100,7 @@ const setupDefaultUser = () => {
.insert({ .insert({
user_id: user.id, user_id: user.id,
type: 'password', type: 'password',
secret: '9KcvfmAvcVonB7YOMqdjJGsTG2JL058Rx6xFNMintAeaGETsRBRlSbfXdi1inoCa', secret: 'iArhP1j7p1P6TA92FA2FMbbUGYqwcYzxC4AVEe12Wbi94FY9gNN62aKyF1shrvG4NycjjX9KfmDQiwkLZH1ZDR9xMjiG2QmoHXi',
meta: {}, meta: {},
}) })
.then(() => { .then(() => {

View File

@@ -17,6 +17,6 @@ services:
# - "CLEAN=false" # Clean folders # - "CLEAN=false" # Clean folders
# - "FULLCLEAN=true" # Clean unused config folders # - "FULLCLEAN=true" # Clean unused config folders
# - "PHP81=true" # Activate PHP81 # - "PHP81=true" # Activate PHP81
# - "PHP81_APKS=php81-curl php-81-curl" # Add php extensions, see aviable packages here: https://pkgs.alpinelinux.org/packages?branch=edge&repo=community&arch=x86_64&name=php81-* # - "PHP81_APKS=php81-curl php-81-curl" # Add php extensions, see aviable packages here: https://pkgs.alpinelinux.org/packages?branch=v3.17&repo=community&arch=x86_64&name=php81-*
# - "PHP82=true" # Activate PHP82 # - "PHP82=true" # Activate PHP82
# - "PHP82_APKS=php82-curl php-82-curl" # Add php extensions, see aviable packages here: https://pkgs.alpinelinux.org/packages?branch=edge&repo=community&arch=x86_64&name=php82-* # - "PHP82_APKS=php82-curl php-82-curl" # Add php extensions, see aviable packages here: https://pkgs.alpinelinux.org/packages?branch=v3.17&repo=community&arch=x86_64&name=php82-*

View File

@@ -132,7 +132,7 @@ module.exports = Mn.View.extend({
let items = this.model.get('items'); let items = this.model.get('items');
let clients = this.model.get('clients'); let clients = this.model.get('clients');
// Ensure at least one field is shown initally // Ensure at least one field is shown initially
if (!items.length) items.push({}); if (!items.length) items.push({});
if (!clients.length) clients.push({}); if (!clients.length) clients.push({});

View File

@@ -268,7 +268,7 @@ module.exports = Mn.View.extend({
this.ui.domain_names.selectize({ this.ui.domain_names.selectize({
delimiter: ',', delimiter: ',',
persist: false, persist: false,
maxOptions: 64, maxOptions: 99,
create: function (input) { create: function (input) {
return { return {
value: input, value: input,

View File

@@ -221,7 +221,7 @@ module.exports = Mn.View.extend({
this.ui.domain_names.selectize({ this.ui.domain_names.selectize({
delimiter: ',', delimiter: ',',
persist: false, persist: false,
maxOptions: 64, maxOptions: 99,
create: function (input) { create: function (input) {
return { return {
value: input, value: input,

View File

@@ -259,7 +259,7 @@ module.exports = Mn.View.extend({
this.ui.domain_names.selectize({ this.ui.domain_names.selectize({
delimiter: ',', delimiter: ',',
persist: false, persist: false,
maxOptions: 64, maxOptions: 99,
create: function (input) { create: function (input) {
return { return {
value: input, value: input,

View File

@@ -223,7 +223,7 @@ module.exports = Mn.View.extend({
this.ui.domain_names.selectize({ this.ui.domain_names.selectize({
delimiter: ',', delimiter: ',',
persist: false, persist: false,
maxOptions: 64, maxOptions: 99,
create: function (input) { create: function (input) {
return { return {
value: input, value: input,

View File

@@ -4,7 +4,7 @@
"description": "A beautiful interface for creating Nginx endpoints", "description": "A beautiful interface for creating Nginx endpoints",
"main": "js/index.js", "main": "js/index.js",
"devDependencies": { "devDependencies": {
"@babel/core": "7.20.12", "@babel/core": "7.21.0",
"babel-core": "6.26.3", "babel-core": "6.26.3",
"babel-loader": "8.3.0", "babel-loader": "8.3.0",
"babel-preset-env": "1.7.0", "babel-preset-env": "1.7.0",

2
rootfs/bin/check-health.sh Normal file → Executable file
View File

@@ -1,6 +1,6 @@
#!/bin/sh #!/bin/sh
if (if [ "$PHP81" = true ]; then cgi-fcgi -bind -connect /dev/php81.sock > /dev/null 2>&1; fi && if [ "$PHP82" = true ]; then cgi-fcgi -bind -connect /dev/php82.sock > /dev/null 2>&1; fi && [ "$(wget -q --no-check-certificate https://127.0.0.1:81/api -O - | jq --raw-output '.status')" = "OK" ]); then if (if [ "$PHP81" = true ]; then cgi-fcgi -bind -connect /dev/php81.sock > /dev/null 2>&1; fi && if [ "$PHP82" = true ]; then cgi-fcgi -bind -connect /dev/php82.sock > /dev/null 2>&1; fi && [ "$(curl -sk https://127.0.0.1:81/api/ | jq --raw-output .status)" = "OK" ]); then
echo "OK" echo "OK"
exit 0 exit 0
else else

38
rootfs/bin/start.sh Normal file → Executable file
View File

@@ -1,10 +1,12 @@
#!/bin/sh #!/bin/sh
apk upgrade --no-cache if [ "$PHP81" = true ] || [ "$PHP82" = true ]; then
apk add --no-cache fcgi
fi
if [ "$PHP81" = "true" ]; then if [ "$PHP81" = "true" ]; then
apk add --no-cache php81 php81-fpm fcgi apk add --no-cache php81-fpm
# From https://github.com/nextcloud/all-in-one/pull/1377/files # From https://github.com/nextcloud/all-in-one/pull/1377/files
if [ -n "$PHP81_APKS" ]; then if [ -n "$PHP81_APKS" ]; then
@@ -45,7 +47,7 @@ fi
if [ "$PHP82" = "true" ]; then if [ "$PHP82" = "true" ]; then
apk add --no-cache php82 php82-fpm fcgi apk add --no-cache php82-fpm
# From https://github.com/nextcloud/all-in-one/pull/1377/files # From https://github.com/nextcloud/all-in-one/pull/1377/files
if [ -n "$PHP82_APKS" ]; then if [ -n "$PHP82_APKS" ]; then
@@ -328,12 +330,14 @@ sed -i "s|#ssl_certificate_key .*|ssl_certificate_key $NPM_KEY;|g" /app/template
if [ -n "$NPM_CHAIN" ]; then sed -i "s|#ssl_trusted_certificate .*|ssl_trusted_certificate $NPM_CHAIN;|g" /app/templates/default.conf || sleep inf; fi if [ -n "$NPM_CHAIN" ]; then sed -i "s|#ssl_trusted_certificate .*|ssl_trusted_certificate $NPM_CHAIN;|g" /app/templates/default.conf || sleep inf; fi
if [ "$NPM_LISTEN_LOCALHOST" = "true" ]; then if [ "$NPM_LISTEN_LOCALHOST" = "true" ]; then
sed -i "s/listen 81/listen 127.0.0.1:81/g" /usr/local/nginx/conf/conf.d/npm.conf || sleep inf sed -i "s|listen 81|listen 127.0.0.1:81|g" /usr/local/nginx/conf/conf.d/npm.conf || sleep inf
sed -i "s/listen \[::\]:81/listen \[::1\]:81/g" /usr/local/nginx/conf/conf.d/npm.conf || sleep inf sed -i "s|listen \[::\]:81|listen \[::1\]:81|g" /usr/local/nginx/conf/conf.d/npm.conf || sleep inf
sed -i "s|listen 81|listen 127.0.0.1:81|g" /usr/local/nginx/conf/conf.d/no-server-name.conf || sleep inf
sed -i "s|listen \[::\]:81|listen \[::1\]:81|g" /usr/local/nginx/conf/conf.d/no-server-name.conf || sleep inf
fi fi
if [ "$NGINX_LOG_NOT_FOUND" = "true" ]; then if [ "$NGINX_LOG_NOT_FOUND" = "true" ]; then
sed -i "s/log_not_found off;/log_not_found on;/g" /usr/local/nginx/conf/nginx.conf || sleep inf sed -i "s|log_not_found off;|log_not_found on;|g" /usr/local/nginx/conf/nginx.conf || sleep inf
fi fi
if [ -z "$NPM_CERT_ID" ]; then if [ -z "$NPM_CERT_ID" ]; then
@@ -363,23 +367,23 @@ if ! nginx -t > /dev/null 2>&1; then
fi fi
if [ "$PHP81" = "true" ]; then if [ "$PHP81" = "true" ]; then
if ! cross-env PHP_INI_SCAN_DIR=/data/php/81/conf.d php-fpm81 -c /data/php/81 -y /data/php/81/php-fpm.conf -FORt > /dev/null 2>&1; then if ! PHP_INI_SCAN_DIR=/data/php/81/conf.d php-fpm81 -c /data/php/81 -y /data/php/81/php-fpm.conf -FORt > /dev/null 2>&1; then
cross-env PHP_INI_SCAN_DIR=/data/php/81/conf.d php-fpm81 -c /data/php/81 -y /data/php/81/php-fpm.conf -FORt || sleep inf PHP_INI_SCAN_DIR=/data/php/81/conf.d php-fpm81 -c /data/php/81 -y /data/php/81/php-fpm.conf -FORt || sleep inf
sleep inf || exit 1 sleep inf || exit 1
fi fi
fi fi
if [ "$PHP82" = "true" ]; then if [ "$PHP82" = "true" ]; then
if ! cross-env PHP_INI_SCAN_DIR=/data/php/82/conf.d php-fpm82 -c /data/php/82 -y /data/php/82/php-fpm.conf -FORt > /dev/null 2>&1; then if ! PHP_INI_SCAN_DIR=/data/php/82/conf.d php-fpm82 -c /data/php/82 -y /data/php/82/php-fpm.conf -FORt > /dev/null 2>&1; then
cross-env PHP_INI_SCAN_DIR=/data/php/82/conf.d php-fpm82 -c /data/php/82 -y /data/php/82/php-fpm.conf -FORt || sleep inf PHP_INI_SCAN_DIR=/data/php/82/conf.d php-fpm82 -c /data/php/82 -y /data/php/82/php-fpm.conf -FORt || sleep inf
sleep inf || exit 1 sleep inf || exit 1
fi fi
fi fi
while (nginx -t > /dev/null 2>&1 && if [ "$PHP81" = true ]; then cross-env PHP_INI_SCAN_DIR=/data/php/81/conf.d php-fpm81 -c /data/php/81 -y /data/php/81/php-fpm.conf -FORt > /dev/null 2>&1; fi && if [ "$PHP82" = true ]; then cross-env PHP_INI_SCAN_DIR=/data/php/82/conf.d php-fpm82 -c /data/php/82 -y /data/php/82/php-fpm.conf -FORt > /dev/null 2>&1; fi); do while (nginx -t > /dev/null 2>&1 && if [ "$PHP81" = true ]; then PHP_INI_SCAN_DIR=/data/php/81/conf.d php-fpm81 -c /data/php/81 -y /data/php/81/php-fpm.conf -FORt > /dev/null 2>&1; fi && if [ "$PHP82" = true ]; then PHP_INI_SCAN_DIR=/data/php/82/conf.d php-fpm82 -c /data/php/82 -y /data/php/82/php-fpm.conf -FORt > /dev/null 2>&1; fi); do
nginx || exit 1 & nginx || exit 1 &
if [ "$PHP81" = "true" ]; then cross-env PHP_INI_SCAN_DIR=/data/php/81/conf.d php-fpm81 -c /data/php/81 -y /data/php/81/php-fpm.conf -FOR || exit 1; fi & if [ "$PHP81" = "true" ]; then PHP_INI_SCAN_DIR=/data/php/81/conf.d php-fpm81 -c /data/php/81 -y /data/php/81/php-fpm.conf -FOR || exit 1; fi &
if [ "$PHP82" = "true" ]; then cross-env PHP_INI_SCAN_DIR=/data/php/82/conf.d php-fpm82 -c /data/php/82 -y /data/php/82/php-fpm.conf -FOR || exit 1; fi & if [ "$PHP82" = "true" ]; then PHP_INI_SCAN_DIR=/data/php/82/conf.d php-fpm82 -c /data/php/82 -y /data/php/82/php-fpm.conf -FOR || exit 1; fi &
node --abort_on_uncaught_exception --max_old_space_size=250 index.js || exit 1 & node --abort_on_uncaught_exception --max_old_space_size=250 index.js || exit 1 &
wait wait
done done
@@ -389,13 +393,13 @@ if ! nginx -t > /dev/null 2>&1; then
fi fi
if [ "$PHP81" = "true" ]; then if [ "$PHP81" = "true" ]; then
if ! cross-env PHP_INI_SCAN_DIR=/data/php/81/conf.d php-fpm81 -c /data/php/81 -y /data/php/81/php-fpm.conf -FORt > /dev/null 2>&1; then if ! PHP_INI_SCAN_DIR=/data/php/81/conf.d php-fpm81 -c /data/php/81 -y /data/php/81/php-fpm.conf -FORt > /dev/null 2>&1; then
cross-env PHP_INI_SCAN_DIR=/data/php/81/conf.d php-fpm81 -c /data/php/81 -y /data/php/81/php-fpm.conf -FORt || sleep inf PHP_INI_SCAN_DIR=/data/php/81/conf.d php-fpm81 -c /data/php/81 -y /data/php/81/php-fpm.conf -FORt || sleep inf
fi fi
fi fi
if [ "$PHP82" = "true" ]; then if [ "$PHP82" = "true" ]; then
if ! cross-env PHP_INI_SCAN_DIR=/data/php/82/conf.d php-fpm82 -c /data/php/82 -y /data/php/82/php-fpm.conf -FORt > /dev/null 2>&1; then if ! PHP_INI_SCAN_DIR=/data/php/82/conf.d php-fpm82 -c /data/php/82 -y /data/php/82/php-fpm.conf -FORt > /dev/null 2>&1; then
cross-env PHP_INI_SCAN_DIR=/data/php/82/conf.d php-fpm82 -c /data/php/82 -y /data/php/82/php-fpm.conf -FORt || sleep inf PHP_INI_SCAN_DIR=/data/php/82/conf.d php-fpm82 -c /data/php/82 -y /data/php/82/php-fpm.conf -FORt || sleep inf
fi fi
fi fi

View File

@@ -1,4 +1,4 @@
brotli on; brotli on;
brotli_types *; brotli_types *;
brotli_comp_level 11; brotli_comp_level 0;
brotli_static on; brotli_static on;

View File

@@ -4,6 +4,8 @@ pcre_jit on;
worker_processes auto; worker_processes auto;
error_log stderr; error_log stderr;
quic_bpf on;
# Custom # Custom
include /data/nginx/custom/root.conf; include /data/nginx/custom/root.conf;
@@ -24,8 +26,11 @@ http {
server_tokens build; server_tokens build;
aio threads; aio threads;
sendfile on; sendfile on;
quic_gso on;
quic_retry on;
tcp_nopush on; tcp_nopush on;
tcp_nodelay on; tcp_nodelay on;
http3_push_preload on;
client_max_body_size 0; client_max_body_size 0;
client_body_buffer_size 512k; client_body_buffer_size 512k;
@@ -33,7 +38,7 @@ http {
gzip_vary on; gzip_vary on;
gzip_types *; gzip_types *;
gzip_proxied any; gzip_proxied any;
gzip_comp_level 9; gzip_comp_level 1;
gunzip on; gunzip on;
gzip_static on; gzip_static on;
@@ -111,6 +116,8 @@ http {
} }
stream { stream {
quic_gso on;
quic_retry on;
# Files generated by NPM # Files generated by NPM
include /data/nginx/stream/*.conf; include /data/nginx/stream/*.conf;

View File

@@ -6,11 +6,12 @@ Expires: 2023-12-31T22:59:00.000Z
Encryption: https://zvcdn.de/publickey.asc Encryption: https://zvcdn.de/publickey.asc
Preferred-Languages: de, en Preferred-Languages: de, en
Canonical: https://npm.zvcdn.de/.well-known/security.txt Canonical: https://npm.zvcdn.de/.well-known/security.txt
Canonical: https://raw.githubusercontent.com/ZoeyVid/nginx-proxy-manager/develop/rootfs/app/frontend/.well-known/security.txt Canonical: https://npm-mx.zvcdn.de/.well-known/security.txt
Canonical: https://raw.githubusercontent.com/ZoeyVid/nginx-proxy-manager/develop/security.txt
-----BEGIN PGP SIGNATURE----- -----BEGIN PGP SIGNATURE-----
iHUEARYKAB0WIQQZsl0LheH0mUz2hsVuOQn3bP/+fAUCY7CHHAAKCRBuOQn3bP/+ iHUEARYKAB0WIQQZsl0LheH0mUz2hsVuOQn3bP/+fAUCY+oWmgAKCRBuOQn3bP/+
fHysAP9ZfBWAtWp+dE1Oow886oGvRGuhikWy31JhFuGa9OjWZgD/UDNXnaTe3m06 fG4EAP9WXH5lT1OXjtNeM44ZaRwdtrm/Z/x515E0TDJ1S6NFTgD/WENwGwBzKApW
D56Zc3GiQIW1QEboXMVmVwX4IEQN7Qk= Qv+aYLdHLBaYnJsj9D3RYjCuijLckQs=
=uSIG =nFDM
-----END PGP SIGNATURE----- -----END PGP SIGNATURE-----