diff --git a/.github/workflows/container-build.yml b/.github/workflows/container-build.yml index b54f37d11..a96362fea 100644 --- a/.github/workflows/container-build.yml +++ b/.github/workflows/container-build.yml @@ -50,6 +50,9 @@ jobs: # Prepare - name: Checkout source code uses: actions/checkout@v3 + - name: Replace VERSION + if: inputs.RELEASE == 'testing' + run: ./misc/update-version.sh testing - name: Setup SSH for ARM node if: inputs.CACHE_SUFFIX == 'arm' run: | diff --git a/.github/workflows/create-arm.yml b/.github/workflows/create-arm.yml index d3770807c..b574d7679 100644 --- a/.github/workflows/create-arm.yml +++ b/.github/workflows/create-arm.yml @@ -39,7 +39,7 @@ jobs: id: scw uses: scaleway/action-scw@bbcfd65cd2af73456ce439088e0d42c1657c4c38 with: - args: instance server create zone=fr-par-2 type=AMP2-C60 root-volume=block:50GB + args: instance server create zone=fr-par-2 type=AMP2-C48 root-volume=block:50GB save-config: true version: v2.13.0 access-key: ${{ secrets.SCW_ACCESS_KEY }} diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml index bfbdef9c6..f9cb57f9e 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/dev.yml @@ -7,7 +7,6 @@ on: branches: [dev] jobs: - # Containers build-containers: strategy: @@ -25,6 +24,7 @@ jobs: uses: ./.github/workflows/container-build.yml with: RELEASE: dev + CACHE: true ARCH: linux/amd64 IMAGE: ${{ matrix.image }} DOCKERFILE: ${{ matrix.dockerfile }} @@ -93,4 +93,29 @@ jobs: RELEASE: dev secrets: PRIVATE_REGISTRY: ${{ secrets.PRIVATE_REGISTRY }} - PRIVATE_REGISTRY_TOKEN: ${{ secrets.PRIVATE_REGISTRY_TOKEN }} \ No newline at end of file + PRIVATE_REGISTRY_TOKEN: ${{ secrets.PRIVATE_REGISTRY_TOKEN }} + + # Push with dev tag + push-dev: + needs: [tests-ui, tests-core] + runs-on: ubuntu-latest + steps: + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_TOKEN }} + - name: Login to private repository + uses: docker/login-action@v2 + with: + registry: ${{ secrets.PRIVATE_REGISTRY }} + username: registry + password: ${{ secrets.PRIVATE_REGISTRY_TOKEN }} + - name: Push BW image + run: docker pull ${{ secrets.PRIVATE_REGISTRY }}/infra/bunkerweb-tests:dev && docker tag ${{ secrets.PRIVATE_REGISTRY }}/infra/bunkerweb-tests:dev bunkerity/bunkerweb:dev && docker push bunkerity/bunkerweb:dev + - name: Push scheduler image + run: docker pull ${{ secrets.PRIVATE_REGISTRY }}/infra/scheduler-tests:dev && docker tag ${{ secrets.PRIVATE_REGISTRY }}/infra/scheduler-tests:dev bunkerity/bunkerweb-scheduler:dev && docker push bunkerity/bunkerweb-scheduler:dev + - name: Push UI image + run: docker pull ${{ secrets.PRIVATE_REGISTRY }}/infra/ui-tests:dev && docker tag ${{ secrets.PRIVATE_REGISTRY }}/infra/ui-tests:dev bunkerity/bunkerweb-ui:dev && docker push bunkerity/bunkerweb-ui:dev + - name: Push autoconf image + run: docker pull ${{ secrets.PRIVATE_REGISTRY }}/infra/autoconf-tests:dev && docker tag ${{ secrets.PRIVATE_REGISTRY }}/infra/autoconf-tests:dev bunkerity/bunkerweb-autoconf:dev && docker push bunkerity/bunkerweb-autoconf:dev diff --git a/.github/workflows/linux-build.yml b/.github/workflows/linux-build.yml index a8ee8b77e..6001899d3 100644 --- a/.github/workflows/linux-build.yml +++ b/.github/workflows/linux-build.yml @@ -42,6 +42,9 @@ jobs: # Prepare - name: Checkout source code uses: actions/checkout@v3 + - name: Replace VERSION + if: inputs.RELEASE == 'testing' + run: ./misc/update-version.sh testing - name: Extract arch run : | echo "ARCH=${{ env.PLATFORMS }}" | sed 's/linux//g' | sed 's@/@@g' >> "$GITHUB_ENV" @@ -90,9 +93,9 @@ jobs: registry: ${{ secrets.PRIVATE_REGISTRY }} username: registry password: ${{ secrets.PRIVATE_REGISTRY_TOKEN }} - # Build staging package image + # Build testing package image - name: Build package image - if: inputs.RELEASE == 'staging' + if: inputs.RELEASE == 'testing' uses: docker/build-push-action@v4 with: context: . @@ -100,11 +103,11 @@ jobs: file: src/linux/Dockerfile-${{ inputs.LINUX }} platforms: ${{ inputs.PLATFORMS }} tags: local/bunkerweb-${{ inputs.LINUX }}:latest - cache-from: type=registry,ref=bunkerity/cache:${{ inputs.LINUX }}-staging - cache-to: type=registry,ref=bunkerity/cache:${{ inputs.LINUX }}-staging,mode=min - # Build non-staging package image + cache-from: type=registry,ref=bunkerity/cache:${{ inputs.LINUX }}-testing + cache-to: type=registry,ref=bunkerity/cache:${{ inputs.LINUX }}-testing,mode=min + # Build non-testing package image - name: Build package image - if: inputs.RELEASE != 'staging' + if: inputs.RELEASE != 'testing' uses: docker/build-push-action@v4 with: context: . diff --git a/.github/workflows/push-doc.yml b/.github/workflows/push-doc.yml index c5802149c..360b37881 100644 --- a/.github/workflows/push-doc.yml +++ b/.github/workflows/push-doc.yml @@ -22,6 +22,9 @@ jobs: with: fetch-depth: 0 token: ${{ secrets.BUNKERBOT_TOKEN }} + - name: Replace VERSION + if: inputs.VERSION == 'testing' + run: ./misc/update-version.sh testing - name: Setup git user run: | git config --global user.name "BunkerBot" diff --git a/.github/workflows/push-github.yml b/.github/workflows/push-github.yml index 3490143ef..f435c0e4f 100644 --- a/.github/workflows/push-github.yml +++ b/.github/workflows/push-github.yml @@ -18,18 +18,29 @@ jobs: - uses: actions/checkout@v3 # Get PDF doc - name: Get documentation + if: inputs.VERSION != 'testing' uses: actions/download-artifact@v3 with: name: BunkerWeb_documentation_v${{ inputs.VERSION }}.pdf # Create tag - uses: rickstaa/action-create-tag@v1 name: Create tag + if: inputs.VERSION != 'testing' with: tag: "v${{ inputs.VERSION }}" message: "v${{ inputs.VERSION }}" force_push_tag: true + # Create tag + - uses: rickstaa/action-create-tag@v1 + name: Create tag + if: inputs.VERSION == 'testing' + with: + tag: "${{ inputs.VERSION }}" + message: "${{ inputs.VERSION }}" + force_push_tag: true # Extract changelog - name: Extract changelog + if: inputs.VERSION != 'testing' id: getchangelog run: | content=$(awk -v n=2 '/##/{n--}; n > 0' CHANGELOG.md | grep -v '# Changelog' | grep -v '##' | sed '/^$/d') @@ -39,6 +50,7 @@ jobs: echo "::set-output name=content::$content" # Create release - name: Create release + if: inputs.VERSION != 'testing' uses: softprops/action-gh-release@v1 with: body: | @@ -60,4 +72,25 @@ jobs: tag_name: v${{ inputs.VERSION }} discussion_category_name: Announcements files: BunkerWeb_documentation_v${{ inputs.VERSION }}.pdf + # Create release + - name: Create release + if: inputs.VERSION == 'testing' + uses: softprops/action-gh-release@v1 + with: + body: | + **The testing version of BunkerWeb should not be used in production, please use the latest stable version instead.** + + Documentation : https://docs.bunkerweb.io/${{ inputs.VERSION }}/ + + Docker tags : + - `bunkerity/bunkerweb:${{ inputs.VERSION }}` + - `bunkerity/bunkerweb-scheduler:${{ inputs.VERSION }}` + - `bunkerity/bunkerweb-autoconf:${{ inputs.VERSION }}` + - `bunkerity/bunkerweb-ui:${{ inputs.VERSION }}` + + Linux packages : https://packagecloud.io/app/bunkerity/bunkerweb/search?q=${{ inputs.VERSION }}&filter=all&dist= + draft: false + prerelease: ${{ inputs.PRERELEASE }} + name: Testing + tag_name: ${{ inputs.VERSION }} diff --git a/.github/workflows/push-packagecloud.yml b/.github/workflows/push-packagecloud.yml index 135203a59..49caa65b0 100644 --- a/.github/workflows/push-packagecloud.yml +++ b/.github/workflows/push-packagecloud.yml @@ -64,6 +64,10 @@ jobs: continue-on-error: true env: PACKAGECLOUD_TOKEN: ${{ secrets.PACKAGECLOUD_TOKEN }} + # Update name + # - name: Rename package + # if: inputs.BW_VERSION == 'testing' + # run: sudo apt install -y rename && rename 's/[0-9]\.[0-9]\.[0-9]/testing/' /tmp/${{ inputs.LINUX }}/*.${{ inputs.PACKAGE }} # Push package - name: Push package to packagecloud uses: danielmundi/upload-packagecloud@v1 diff --git a/.github/workflows/staging-tests.yml b/.github/workflows/staging-tests.yml index 5248e340e..c642bae62 100644 --- a/.github/workflows/staging-tests.yml +++ b/.github/workflows/staging-tests.yml @@ -33,13 +33,13 @@ jobs: username: registry password: ${{ secrets.PRIVATE_REGISTRY_TOKEN }} - name: Pull BW image - run: docker pull ${{ secrets.PRIVATE_REGISTRY }}/infra/bunkerweb-tests:staging && docker tag ${{ secrets.PRIVATE_REGISTRY }}/infra/bunkerweb-tests:staging local/bunkerweb-tests:latest + run: docker pull ${{ secrets.PRIVATE_REGISTRY }}/infra/bunkerweb-tests:testing && docker tag ${{ secrets.PRIVATE_REGISTRY }}/infra/bunkerweb-tests:testing local/bunkerweb-tests:latest if: contains(fromJSON('["linux", "k8s"]'), inputs.TYPE) != true - name: Pull Scheduler image - run: docker pull ${{ secrets.PRIVATE_REGISTRY }}/infra/scheduler-tests:staging && docker tag ${{ secrets.PRIVATE_REGISTRY }}/infra/scheduler-tests:staging local/scheduler-tests:latest + run: docker pull ${{ secrets.PRIVATE_REGISTRY }}/infra/scheduler-tests:testing && docker tag ${{ secrets.PRIVATE_REGISTRY }}/infra/scheduler-tests:testing local/scheduler-tests:latest if: contains(fromJSON('["linux", "k8s"]'), inputs.TYPE) != true - name: Pull Autoconf image - run: docker pull ${{ secrets.PRIVATE_REGISTRY }}/infra/autoconf-tests:staging && docker tag ${{ secrets.PRIVATE_REGISTRY }}/infra/autoconf-tests:staging local/autoconf-tests:latest + run: docker pull ${{ secrets.PRIVATE_REGISTRY }}/infra/autoconf-tests:testing && docker tag ${{ secrets.PRIVATE_REGISTRY }}/infra/autoconf-tests:testing local/autoconf-tests:latest if: contains(fromJSON('["autoconf", "swarm"]'), inputs.TYPE) - name: Push images to local repo run: docker tag local/bunkerweb-tests:latest 192.168.42.100:5000/bunkerweb-tests:latest && docker push 192.168.42.100:5000/bunkerweb-tests:latest && docker tag local/scheduler-tests:latest 192.168.42.100:5000/scheduler-tests:latest && docker push 192.168.42.100:5000/scheduler-tests:latest && docker tag local/autoconf-tests:latest 192.168.42.100:5000/autoconf-tests:latest && docker push 192.168.42.100:5000/autoconf-tests:latest @@ -59,19 +59,19 @@ jobs: if: inputs.TYPE == 'k8s' - name: Pull BW linux ubuntu test image if: inputs.TYPE == 'linux' - run: docker pull ${{ secrets.PRIVATE_REGISTRY }}/infra/ubuntu-tests:staging && docker tag ${{ secrets.PRIVATE_REGISTRY }}/infra/ubuntu-tests:staging local/ubuntu:latest + run: docker pull ${{ secrets.PRIVATE_REGISTRY }}/infra/ubuntu-tests:testing && docker tag ${{ secrets.PRIVATE_REGISTRY }}/infra/ubuntu-tests:testing local/ubuntu:latest - name: Pull BW linux debian test image if: inputs.TYPE == 'linux' - run: docker pull ${{ secrets.PRIVATE_REGISTRY }}/infra/debian-tests:staging && docker tag ${{ secrets.PRIVATE_REGISTRY }}/infra/debian-tests:staging local/debian:latest + run: docker pull ${{ secrets.PRIVATE_REGISTRY }}/infra/debian-tests:testing && docker tag ${{ secrets.PRIVATE_REGISTRY }}/infra/debian-tests:testing local/debian:latest # - name: Pull BW linux centos test image # if: inputs.TYPE == 'linux' - # run: docker pull ${{ secrets.PRIVATE_REGISTRY }}/infra/centos-tests:staging && docker tag ${{ secrets.PRIVATE_REGISTRY }}/infra/centos-tests:staging local/centos:latest + # run: docker pull ${{ secrets.PRIVATE_REGISTRY }}/infra/centos-tests:testing && docker tag ${{ secrets.PRIVATE_REGISTRY }}/infra/centos-tests:testing local/centos:latest - name: Pull BW linux fedora test image if: inputs.TYPE == 'linux' - run: docker pull ${{ secrets.PRIVATE_REGISTRY }}/infra/fedora-tests:staging && docker tag ${{ secrets.PRIVATE_REGISTRY }}/infra/fedora-tests:staging local/fedora:latest + run: docker pull ${{ secrets.PRIVATE_REGISTRY }}/infra/fedora-tests:testing && docker tag ${{ secrets.PRIVATE_REGISTRY }}/infra/fedora-tests:testing local/fedora:latest - name: Pull BW linux rhel test image if: inputs.TYPE == 'linux' - run: docker pull ${{ secrets.PRIVATE_REGISTRY }}/infra/rhel-tests:staging && docker tag ${{ secrets.PRIVATE_REGISTRY }}/infra/rhel-tests:staging local/rhel:latest + run: docker pull ${{ secrets.PRIVATE_REGISTRY }}/infra/rhel-tests:testing && docker tag ${{ secrets.PRIVATE_REGISTRY }}/infra/rhel-tests:testing local/rhel:latest # Do tests - name: Run tests if: inputs.TYPE == 'docker' @@ -99,7 +99,7 @@ jobs: ROOT_DOMAIN: ${{ secrets.ROOT_DOMAIN }} KUBECONFIG: "/tmp/k8s/kubeconfig" PRIVATE_REGISTRY: ${{ secrets.PRIVATE_REGISTRY }} - IMAGE_TAG: "staging" + IMAGE_TAG: "testing" - name: Run Linux ubuntu tests if: inputs.TYPE == 'linux' run: export $(echo "$TEST_DOMAINS" | xargs) && ./tests/main.py "linux" "ubuntu" diff --git a/.github/workflows/staging.yml b/.github/workflows/staging.yml index 072b009cf..f777ee8a1 100644 --- a/.github/workflows/staging.yml +++ b/.github/workflows/staging.yml @@ -24,7 +24,7 @@ jobs: dockerfile: src/ui/Dockerfile uses: ./.github/workflows/container-build.yml with: - RELEASE: staging + RELEASE: testing ARCH: linux/amd64 CACHE: true PUSH: true @@ -52,7 +52,7 @@ jobs: package: rpm uses: ./.github/workflows/linux-build.yml with: - RELEASE: staging + RELEASE: testing LINUX: ${{ matrix.linux }} PACKAGE: ${{ matrix.package }} TEST: true @@ -125,7 +125,7 @@ jobs: needs: [create-infras] uses: ./.github/workflows/tests-ui.yml with: - RELEASE: staging + RELEASE: testing secrets: PRIVATE_REGISTRY: ${{ secrets.PRIVATE_REGISTRY }} PRIVATE_REGISTRY_TOKEN: ${{ secrets.PRIVATE_REGISTRY_TOKEN }} @@ -150,7 +150,7 @@ jobs: uses: ./.github/workflows/test-core.yml with: TEST: ${{ matrix.test }} - RELEASE: staging + RELEASE: testing secrets: PRIVATE_REGISTRY: ${{ secrets.PRIVATE_REGISTRY }} PRIVATE_REGISTRY_TOKEN: ${{ secrets.PRIVATE_REGISTRY_TOKEN }} @@ -166,4 +166,108 @@ jobs: with: TYPE: ${{ matrix.type }} secrets: - CICD_SECRETS: ${{ secrets.CICD_SECRETS }} \ No newline at end of file + CICD_SECRETS: ${{ secrets.CICD_SECRETS }} + + # Push Docker images + push-images: + needs: [staging-tests, tests-ui, tests-core] + runs-on: ubuntu-latest + steps: + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_TOKEN }} + - name: Login to private repository + uses: docker/login-action@v2 + with: + registry: ${{ secrets.PRIVATE_REGISTRY }} + username: registry + password: ${{ secrets.PRIVATE_REGISTRY_TOKEN }} + - name: Push BW image + run: docker pull ${{ secrets.PRIVATE_REGISTRY }}/infra/bunkerweb-tests:testing && docker tag ${{ secrets.PRIVATE_REGISTRY }}/infra/bunkerweb-tests:testing bunkerity/bunkerweb:testing && docker push bunkerity/bunkerweb:testing + - name: Push scheduler image + run: docker pull ${{ secrets.PRIVATE_REGISTRY }}/infra/scheduler-tests:testing && docker tag ${{ secrets.PRIVATE_REGISTRY }}/infra/scheduler-tests:testing bunkerity/bunkerweb-scheduler:testing && docker push bunkerity/bunkerweb-scheduler:testing + - name: Push UI image + run: docker pull ${{ secrets.PRIVATE_REGISTRY }}/infra/ui-tests:testing && docker tag ${{ secrets.PRIVATE_REGISTRY }}/infra/ui-tests:testing bunkerity/bunkerweb-ui:testing && docker push bunkerity/bunkerweb-ui:testing + - name: Push autoconf image + run: docker pull ${{ secrets.PRIVATE_REGISTRY }}/infra/autoconf-tests:testing && docker tag ${{ secrets.PRIVATE_REGISTRY }}/infra/autoconf-tests:testing bunkerity/bunkerweb-autoconf:testing && docker push bunkerity/bunkerweb-autoconf:testing + + # Push Linux packages + push-packages: + needs: [staging-tests, tests-ui, tests-core] + strategy: + matrix: + linux: [ubuntu, debian, fedora, el] + arch: [amd64] + include: + - release: testing + repo: bunkerweb + - linux: ubuntu + separator: _ + suffix: "" + version: jammy + package: deb + - linux: debian + separator: _ + suffix: "" + version: bullseye + package: deb + - linux: fedora + separator: "-" + suffix: "1." + version: 38 + package: rpm + - linux: el + separator: "-" + suffix: "1." + version: 8 + package: rpm + - linux: ubuntu + arch: amd64 + package_arch: amd64 + - linux: debian + arch: amd64 + package_arch: amd64 + - linux: fedora + arch: amd64 + package_arch: x86_64 + - linux: el + arch: amd64 + package_arch: x86_64 + uses: ./.github/workflows/push-packagecloud.yml + with: + SEPARATOR: ${{ matrix.separator }} + SUFFIX: ${{ matrix.suffix }} + REPO: ${{ matrix.repo }} + LINUX: ${{ matrix.linux }} + VERSION: ${{ matrix.version }} + PACKAGE: ${{ matrix.package }} + BW_VERSION: ${{ matrix.release }} + PACKAGE_ARCH: ${{ matrix.package_arch }} + ARCH: ${{ matrix.arch }} + secrets: + PACKAGECLOUD_TOKEN: ${{ secrets.PACKAGECLOUD_TOKEN }} + + # Push doc + push-doc: + needs: [push-images, push-packages] + permissions: + contents: write + uses: ./.github/workflows/push-doc.yml + with: + VERSION: testing + ALIAS: unstable + secrets: + BUNKERBOT_TOKEN: ${{ secrets.BUNKERBOT_TOKEN }} + + # Push on GH + push-gh: + needs: [push-doc] + permissions: + contents: write + discussions: write + uses: ./.github/workflows/push-github.yml + with: + VERSION: testing + PRERELEASE: true \ No newline at end of file diff --git a/.github/workflows/test-core.yml b/.github/workflows/test-core.yml index 0433b44f1..7206f6a39 100644 --- a/.github/workflows/test-core.yml +++ b/.github/workflows/test-core.yml @@ -31,10 +31,15 @@ jobs: run: docker pull ${{ secrets.PRIVATE_REGISTRY }}/infra/bunkerweb-tests:${{ inputs.RELEASE }} && docker tag ${{ secrets.PRIVATE_REGISTRY }}/infra/bunkerweb-tests:${{ inputs.RELEASE }} bunkerweb-tests - name: Pull Scheduler image run: docker pull ${{ secrets.PRIVATE_REGISTRY }}/infra/scheduler-tests:${{ inputs.RELEASE }} && docker tag ${{ secrets.PRIVATE_REGISTRY }}/infra/scheduler-tests:${{ inputs.RELEASE }} scheduler-tests + # Temp fix "is not connected to the network" until compose v2.19.1 is available + - name: Downgrade compose + run: | + sudo apt update + sudo apt install -y --allow-downgrades moby-compose=2.18.1+azure-ubuntu22.04u2 # Run test - name: Run test run: | cd ./tests/core/${{ inputs.TEST }} find . -type f -name 'docker-compose.*' -exec sed -i "s@bunkerity/bunkerweb:.*@bunkerweb-tests@" {} \; find . -type f -name 'docker-compose.*' -exec sed -i "s@bunkerity/bunkerweb-scheduler:.*@scheduler-tests@" {} \; - ./test.sh \ No newline at end of file + ./test.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index f2fb073c3..54a1b0dae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,64 @@ # Changelog +## v1.5.1 - 2023/08/08 + +- [BUGFIX] New version checker in logs displays "404 not found" +- [BUGFIX] New version checker in UI +- [BUGFIX] Only get the right keys from plugin.json files when importing plugins +- [BUGFIX] Remove external resources for Google fonts in UI +- [BUGFIX] Support multiple plugin uploads in one zip when using the UI +- [BUGFIX] Variable being ignored instead of saved in the database when value is empty +- [BUGFIX] ALLOWED_METHODS regex working with LOCK/UNLOCK methods +- [BUGFIX] Custom certificate bug after the refactoring +- [BUGFIX] Wrong variables in header phase (fix CORS feature too) +- [BUGFIX] UI not working in Ubuntu (python zope module) +- [BUGFIX] Patch ModSecurity to run it after LUA code (should fix whitelist problems) +- [BUGFIX] Custom configurations from env were not being deleted properly +- [BUGFIX] Missing concepts image not displayed in the documentation +- [BUGFIX] Scheduler not picking up new instances IPs in autoconf modes +- [BUGFIX] Autoconf deadlock in k8s +- [BUGFIX] Missing HTTP and HTTPS ports for temp nginx +- [BUGFIX] Infinite loop when sessions is not valid +- [BUGFIX] Missing valid LE certificates in edge cases +- [BUGFIX] Wrong service namespace in k8s +- [BUGFIX] DNS_RESOLVERS regex not accepting hostnames +- [PERFORMANCE] Reduce CPU and RAM usage of scheduler +- [PERFORMANCE] Cache ngx.ctx instead of loading it each time +- [PERFORMANCE] Use per-worker LRU cache for common RO LUA values +- [FEATURE] Add Turnstile antibot mode +- [FEATURE] Add more CORS headers +- [FEATURE] Add KEEP_UPSTREAM_HEADERS to preserve headers when using reverse proxy +- [FEATURE] Add the possibility to download the different lists and plugins from a local file (like the blacklist) +- [FEATURE] External plugins can now be downloaded from a tar.gz and tar.xz file as well as zip +- [FEATURE] Add X-Forwarded-Prefix header when using reverse proxy +- [FEATURE] Add REDIRECT_TO_STATUS_CODE to choose status code 301 or 302 when redirecting +- [DOCUMENTATION] Add timezone information +- [DOCUMENTATION] Add timezone informat +- [MISC] Add LOG_LEVEL=warning for docker socket proxy in docs, examples and boilerplates +- [MISC] Temp remove VMWare provider for Vagrant integration +- [MISC] Remove X-Script-Name header and ABSOLUTE_URI variable when using UI +- [MISC] Move logs to /var/log/bunkerweb folder +- [MISC] Reduce "Got an error reading communication packets" warnings in mariadb/mysql + +## v1.5.0 - 2023/05/23 + +- Refactoring of almost all the components of the project +- Dedicated scheduler service to manage jobs and configuration +- Store configuration in a database backend +- Improved web UI and make it working with all integrations +- Improved internal LUA code +- Improved internal cache of BW +- Add Redis support when using clustered integrations +- Add RHEL integration +- Add Vagrant integration +- Init support of generic TCP/UDP (stream) +- Init support of IPv6 +- Improved CI/CD : UI tests, core tests and release automation +- Reduce Docker images size +- Fix and improved core plugins : antibot, cors, dnsbl, ... +- Use PCRE regex instead of LUA patterns +- Connectivity tests at startup/reload with logging + ## v1.5.0-beta - 2023/05/02 - Refactoring of almost all the components of the project diff --git a/README.md b/README.md index 000125e16..ea4160884 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- BunkerWeb logo + BunkerWeb logo

@@ -17,7 +17,7 @@ | 👨‍đŸ’ģ Demo | - đŸ›Ąī¸ Examples + đŸ›Ąī¸ Examples | đŸ’Ŧ Chat | @@ -33,14 +33,14 @@ # BunkerWeb

- overview + overview

BunkerWeb is a next-generation and open-source Web Application Firewall (WAF). -Being a full-featured web server (based on [NGINX](https://nginx.org/) under the hood), it will protect your web services to make them "secure by default". BunkerWeb integrates seamlessly into your existing environments ([Linux](https://docs.bunkerweb.io/1.5.0/integrations/#linux), [Docker](https://docs.bunkerweb.io/1.5.0/integrations/#docker), [Swarm](https://docs.bunkerweb.io/1.5.0/integrations/#swarm), [Kubernetes](https://docs.bunkerweb.io/1.5.0/integrations/#kubernetes), â€Ļ) and is fully configurable (don't panic, there is an [awesome web UI](https://docs.bunkerweb.io/1.5.0/web-ui/) if you don't like the CLI) to meet your own use-cases . In other words, cybersecurity is no more a hassle. +Being a full-featured web server (based on [NGINX](https://nginx.org/) under the hood), it will protect your web services to make them "secure by default". BunkerWeb integrates seamlessly into your existing environments ([Linux](https://docs.bunkerweb.io/1.5.1/integrations/#linux), [Docker](https://docs.bunkerweb.io/1.5.1/integrations/#docker), [Swarm](https://docs.bunkerweb.io/1.5.1/integrations/#swarm), [Kubernetes](https://docs.bunkerweb.io/1.5.1/integrations/#kubernetes), â€Ļ) and is fully configurable (don't panic, there is an [awesome web UI](https://docs.bunkerweb.io/1.5.1/web-ui/) if you don't like the CLI) to meet your own use-cases . In other words, cybersecurity is no more a hassle. -BunkerWeb contains primary [security features](https://docs.bunkerweb.io/1.5.0/security-tuning/) as part of the core but can be easily extended with additional ones thanks to a [plugin system](https://docs.bunkerweb.io/1.5.0/plugins/)). +BunkerWeb contains primary [security features](https://docs.bunkerweb.io/1.5.1/security-tuning/) as part of the core but can be easily extended with additional ones thanks to a [plugin system](https://docs.bunkerweb.io/1.5.1/plugins/)). ## Why BunkerWeb ? @@ -64,12 +64,12 @@ A non-exhaustive list of security features : - **Block known bad IPs** with external blacklists and DNSBL - And much more ... -Learn more about the core security features in the [security tuning](https://docs.bunkerweb.io/1.5.0/security-tuning/) section of the documentation. +Learn more about the core security features in the [security tuning](https://docs.bunkerweb.io/1.5.1/security-tuning/) section of the documentation. ## Demo

- BunkerWeb demo + BunkerWeb demo

A demo website protected with BunkerWeb is available at [demo.bunkerweb.io](https://demo.bunkerweb.io). Feel free to visit it and perform some security tests. @@ -77,10 +77,10 @@ A demo website protected with BunkerWeb is available at [demo.bunkerweb.io](http # Concepts

- BunkerWeb logo + BunkerWeb logo

-You will find more information about the key concepts of BunkerWeb in the [documentation](https://docs.bunkerweb.io/1.5.0/concepts). +You will find more information about the key concepts of BunkerWeb in the [documentation](https://docs.bunkerweb.io/1.5.1/concepts). ## Integrations @@ -88,13 +88,13 @@ The first concept is the integration of BunkerWeb into the target environment. W The following integrations are officially supported : -- [Docker](https://docs.bunkerweb.io/1.5.0/integrations/#docker) -- [Docker autoconf](https://docs.bunkerweb.io/1.5.0/integrations/#docker-autoconf) -- [Swarm](https://docs.bunkerweb.io/1.5.0/integrations/#swarm) -- [Kubernetes](https://docs.bunkerweb.io/1.5.0/integrations/#kubernetes) -- [Linux](https://docs.bunkerweb.io/1.5.0/integrations/#linux) -- [Ansible](https://docs.bunkerweb.io/1.5.0/integrations/#ansible) -- [Vagrant](https://docs.bunkerweb.io/1.5.0/integrations/#vagrant) +- [Docker](https://docs.bunkerweb.io/1.5.1/integrations/#docker) +- [Docker autoconf](https://docs.bunkerweb.io/1.5.1/integrations/#docker-autoconf) +- [Swarm](https://docs.bunkerweb.io/1.5.1/integrations/#swarm) +- [Kubernetes](https://docs.bunkerweb.io/1.5.1/integrations/#kubernetes) +- [Linux](https://docs.bunkerweb.io/1.5.1/integrations/#linux) +- [Ansible](https://docs.bunkerweb.io/1.5.1/integrations/#ansible) +- [Vagrant](https://docs.bunkerweb.io/1.5.1/integrations/#vagrant) ## Settings @@ -126,7 +126,7 @@ When multisite mode is enabled, BunkerWeb will serve and protect multiple web ap ## Custom configurations -Because meeting all the use cases only using the settings is not an option (even with [external plugins](https://docs.bunkerweb.io/1.5.0/plugins)), you can use custom configurations to solve your specific challenges. +Because meeting all the use cases only using the settings is not an option (even with [external plugins](https://docs.bunkerweb.io/1.5.1/plugins)), you can use custom configurations to solve your specific challenges. Under the hood, BunkerWeb uses the notorious NGINX web server, that's why you can leverage its configuration system for your specific needs. Custom NGINX configurations can be included in different [contexts](https://docs.nginx.com/nginx/admin-guide/basic-functionality/managing-configuration-files/#contexts) like HTTP or server (all servers and/or specific server block). @@ -160,7 +160,7 @@ In other words, the scheduler is the brain of BunkerWeb. ## Docker

- Docker + Docker

We provide ready to use prebuilt images for x64, x86, armv7 and arm64 platforms on [Docker Hub](https://hub.docker.com/u/bunkerity). @@ -171,46 +171,46 @@ Docker integration key concepts are : - **Scheduler** container to store configuration and execute jobs - **Networks** to expose ports for clients and connect to upstream web services -You will find more information in the [Docker integration section](https://docs.bunkerweb.io/1.5.0/integrations/#docker) of the documentation. +You will find more information in the [Docker integration section](https://docs.bunkerweb.io/1.5.1/integrations/#docker) of the documentation. ## Docker autoconf

- Docker autoconf + Docker autoconf

The downside of using environment variables is that the container needs to be recreated each time there is an update which is not very convenient. To counter that issue, you can use another image called **autoconf** which will listen for Docker events and automatically reconfigure BunkerWeb in real-time without recreating the container. Instead of defining environment variables for the BunkerWeb container, you simply add **labels** to your web applications containers and the **autoconf** will "automagically" take care of the rest. -You will find more information in the [Docker autoconf section](https://docs.bunkerweb.io/1.5.0/integrations/#docker-autoconf) of the documentation. +You will find more information in the [Docker autoconf section](https://docs.bunkerweb.io/1.5.1/integrations/#docker-autoconf) of the documentation. ## Swarm

- Swarm + Swarm

To automatically configure BunkerWeb instances, a special service, called **autoconf** will listen for Docker Swarm events like service creation or deletion and automatically configure the **BunkerWeb instances** in real-time without downtime. -Like the [Docker autoconf integration](https://docs.bunkerweb.io/1.5.0/integrations/#docker-autoconf), configuration for web services is defined using labels starting with the special **bunkerweb.** prefix. +Like the [Docker autoconf integration](https://docs.bunkerweb.io/1.5.1/integrations/#docker-autoconf), configuration for web services is defined using labels starting with the special **bunkerweb.** prefix. -You will find more information in the [Swarm section](https://docs.bunkerweb.io/1.5.0/integrations/#swarm) of the documentation. +You will find more information in the [Swarm section](https://docs.bunkerweb.io/1.5.1/integrations/#swarm) of the documentation. ## Kubernetes

- Kubernetes + Kubernetes

The autoconf acts as an [Ingress controller](https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/) and will configure the BunkerWeb instances according to the [Ingress resources](https://kubernetes.io/docs/concepts/services-networking/ingress/). It also monitors other Kubernetes objects like [ConfigMap](https://kubernetes.io/docs/concepts/configuration/configmap/) for custom configurations. -You will find more information in the [Kubernetes section](https://docs.bunkerweb.io/1.5.0/integrations/#kubernetes) of the documentation. +You will find more information in the [Kubernetes section](https://docs.bunkerweb.io/1.5.1/integrations/#kubernetes) of the documentation. ## Linux

- Linux + Linux

List of supported Linux distros : @@ -222,12 +222,12 @@ List of supported Linux distros : Repositories of Linux packages for BunkerWeb are available on [PackageCloud](https://packagecloud.io/bunkerity/bunkerweb), they provide a bash script to automatically add and trust the repository (but you can also follow the [manual installation](https://packagecloud.io/bunkerity/bunkerweb/install) instructions if you prefer). -You will find more information in the [Linux section](https://docs.bunkerweb.io/1.5.0/integrations/#linux) of the documentation. +You will find more information in the [Linux section](https://docs.bunkerweb.io/1.5.1/integrations/#linux) of the documentation. ## Ansible

- Ansible + Ansible

List of supported Linux distros : @@ -241,21 +241,20 @@ List of supported Linux distros : A specific BunkerWeb Ansible role is available on [Ansible Galaxy](https://galaxy.ansible.com/bunkerity/bunkerweb) (source code is available [here](https://github.com/bunkerity/bunkerweb-ansible)). -You will find more information in the [Ansible section](https://docs.bunkerweb.io/1.5.0/integrations/#ansible) of the documentation. +You will find more information in the [Ansible section](https://docs.bunkerweb.io/1.5.1/integrations/#ansible) of the documentation. ## Vagrant We maintain ready to use Vagrant boxes hosted on Vagrant cloud for the following providers : -- vmware_desktop -- virtualbox +- virtualbox - libvirt -You will find more information in the [Vagrant section](https://docs.bunkerweb.io/1.5.0/integrations/#vagrant) of the documentation. +You will find more information in the [Vagrant section](https://docs.bunkerweb.io/1.5.1/integrations/#vagrant) of the documentation. # Quickstart guide -Once you have setup BunkerWeb with the integration of your choice, you can follow the [quickstart guide](https://docs.bunkerweb.io/1.5.0/quickstart-guide/) that will cover the following common use cases : +Once you have setup BunkerWeb with the integration of your choice, you can follow the [quickstart guide](https://docs.bunkerweb.io/1.5.1/quickstart-guide/) that will cover the following common use cases : - Protecting a single HTTP application - Protecting multiple HTTP application @@ -266,9 +265,9 @@ Once you have setup BunkerWeb with the integration of your choice, you can follo # Security tuning -BunkerWeb offers many security features that you can configure with [settings](https://docs.bunkerweb.io/1.5.0/settings). Even if the default values of settings ensure a minimal "security by default", we strongly recommend you to tune them. By doing so you will be able to ensure a security level of your choice but also manage false positives. +BunkerWeb offers many security features that you can configure with [settings](https://docs.bunkerweb.io/1.5.1/settings). Even if the default values of settings ensure a minimal "security by default", we strongly recommend you to tune them. By doing so you will be able to ensure a security level of your choice but also manage false positives. -You will find more information in the [security tuning section](https://docs.bunkerweb.io/1.5.0/security-tuning) of the documentation. +You will find more information in the [security tuning section](https://docs.bunkerweb.io/1.5.1/security-tuning) of the documentation. # Settings @@ -278,7 +277,7 @@ As a general rule when multisite mode is enabled, if you want to apply settings When settings are considered as "multiple", it means that you can have multiple groups of settings for the same feature by adding numbers as suffix like `REVERSE_PROXY_URL_1=/subdir`, `REVERSE_PROXY_HOST_1=http://myhost1`, `REVERSE_PROXY_URL_2=/anotherdir`, `REVERSE_PROXY_HOST_2=http://myhost2`, ... for example. -Check the [settings section](https://docs.bunkerweb.io/1.5.0/settings) of the documentation to get the full list. +Check the [settings section](https://docs.bunkerweb.io/1.5.1/settings) of the documentation to get the full list. # Web UI @@ -296,7 +295,7 @@ The "Web UI" is a web application that helps you manage your BunkerWeb instance - Monitor jobs execution - View the logs and search pattern -You will find more information in the [Web UI section](https://docs.bunkerweb.io/1.5.0/web-ui) of the documentation. +You will find more information in the [Web UI section](https://docs.bunkerweb.io/1.5.1/web-ui) of the documentation. # Plugins @@ -304,15 +303,17 @@ BunkerWeb comes with a plugin system to make it possible to easily add new featu Here is the list of "official" plugins that we maintain (see the [bunkerweb-plugins](https://github.com/bunkerity/bunkerweb-plugins) repository for more information) : -| Name | Version | Description | Link | -| :------------: | :-----: | :------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------: | -| **ClamAV** | 0.1 | Automatically scans uploaded files with the ClamAV antivirus engine and denies the request when a file is detected as malicious. | [bunkerweb-plugins/clamav](https://github.com/bunkerity/bunkerweb-plugins/tree/main/clamav) | -| **CrowdSec** | 0.1 | CrowdSec bouncer for BunkerWeb. | [bunkerweb-plugins/crowdsec](https://github.com/bunkerity/bunkerweb-plugins/tree/main/crowdsec) | -| **Discord** | 0.1 | Send security notifications to a Discord channel using a Webhook. | [bunkerweb-plugins/discord](https://github.com/bunkerity/bunkerweb-plugins/tree/main/discord) | -| **Slack** | 0.1 | Send security notifications to a Slack channel using a Webhook. | [bunkerweb-plugins/slack](https://github.com/bunkerity/bunkerweb-plugins/tree/main/slack) | -| **VirusTotal** | 0.1 | Automatically scans uploaded files with the VirusTotal API and denies the request when a file is detected as malicious. | [bunkerweb-plugins/virustotal](https://github.com/bunkerity/bunkerweb-plugins/tree/main/virustotal) | +| Name | Version | Description | Link | +| :------------: | :-----: | :------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------: | +| **ClamAV** | 1.1 | Automatically scans uploaded files with the ClamAV antivirus engine and denies the request when a file is detected as malicious. | [bunkerweb-plugins/clamav](https://github.com/bunkerity/bunkerweb-plugins/tree/main/clamav) | +| **Coraza** | 1.1 | Inspect requests using a the Coraza WAF (alternative of ModSecurity). | [bunkerweb-plugins/coraza](https://github.com/bunkerity/bunkerweb-plugins/tree/main/coraza) | +| **CrowdSec** | 1.1 | CrowdSec bouncer for BunkerWeb. | [bunkerweb-plugins/crowdsec](https://github.com/bunkerity/bunkerweb-plugins/tree/main/crowdsec) | +| **Discord** | 1.1 | Send security notifications to a Discord channel using a Webhook. | [bunkerweb-plugins/discord](https://github.com/bunkerity/bunkerweb-plugins/tree/main/discord) | +| **Slack** | 1.1 | Send security notifications to a Slack channel using a Webhook. | [bunkerweb-plugins/slack](https://github.com/bunkerity/bunkerweb-plugins/tree/main/slack) | +| **VirusTotal** | 1.1 | Automatically scans uploaded files with the VirusTotal API and denies the request when a file is detected as malicious. | [bunkerweb-plugins/virustotal](https://github.com/bunkerity/bunkerweb-plugins/tree/main/virustotal) | +| **WebHook** | 1.1 | Send security notifications to a custom HTTP endpoint using a Webhook. | [bunkerweb-plugins/slack](https://github.com/bunkerity/bunkerweb-plugins/tree/main/webhook) | -You will find more information in the [plugins section](https://docs.bunkerweb.io/1.5.0/plugins) of the documentation. +You will find more information in the [plugins section](https://docs.bunkerweb.io/1.5.1/plugins) of the documentation. # Support @@ -340,12 +341,12 @@ Please don't use [GitHub issues](https://github.com/bunkerity/bunkerweb/issues) # License -This project is licensed under the terms of the [GNU Affero General Public License (AGPL) version 3](https://github.com/bunkerity/bunkerweb/tree/1.5.0/LICENSE.md). +This project is licensed under the terms of the [GNU Affero General Public License (AGPL) version 3](https://github.com/bunkerity/bunkerweb/tree/1.5.1/LICENSE.md). # Contribute -If you would like to contribute to the plugins you can read the [contributing guidelines](https://github.com/bunkerity/bunkerweb/tree/1.5.0/CONTRIBUTING.md) to get started. +If you would like to contribute to the plugins you can read the [contributing guidelines](https://github.com/bunkerity/bunkerweb/tree/1.5.1/CONTRIBUTING.md) to get started. # Security policy -We take security bugs as serious issues and encourage responsible disclosure, see our [security policy](https://github.com/bunkerity/bunkerweb/tree/1.5.0/SECURITY.md) for more information. \ No newline at end of file +We take security bugs as serious issues and encourage responsible disclosure, see our [security policy](https://github.com/bunkerity/bunkerweb/tree/1.5.1/SECURITY.md) for more information. diff --git a/SECURITY.md b/SECURITY.md index 560b97f37..4727f3b5e 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -4,7 +4,7 @@ Even though this project is focused on security, it is still prone to possible v ## Responsible disclosure -If you have found a security bug, please send us an email at security \[@\] bunkerity.com with technical details so we can resolve it as soon as possible. +If you have found a security bug, please send us an email at security \[@\] bunkerity.com (using a ProtonMail if possible) with technical details so we can resolve it as soon as possible. Here is a non-exhaustive list of issues we consider as high risk : - Vulnerability in the code diff --git a/docs/assets/img/bunkerweb_db.svg b/docs/assets/img/bunkerweb_db.svg new file mode 100644 index 000000000..d7f898638 --- /dev/null +++ b/docs/assets/img/bunkerweb_db.svg @@ -0,0 +1 @@ +1**11*1*1*1*1**1*11*bw_selectssetting_idvarchar[256]valuevarchar[256]bw_settingsidvarchar[256]namevarchar[256]plugin_idvarchar[64]contextcontexesdefaultvarchar[4096]helpvarchar[512]labelvarchar[256]regexvarchar[1024]typesettings_typesmultiplevarchar[128]bw_services_settingsservice_idvarchar[64]setting_idvarchar[256]valuevarchar[4096]suffixintmethodmethodsbw_servicesidvarchar[64]methodmethodsbw_global_valuessetting_idvarchar[256]valuevarchar[4096]suffixintmethodmethodsbw_pluginsidvarchar[64]namevarchar[128]descriptionvarchar[256]versionvarchar[32]streamvarchar[16]externalbooleanmethodmethodsdatalongblobchecksumvarchar[128]bw_jobsnamevarchar[128]plugin_idvarchar[64]file_namevarchar[256]everyschedulesreloadbooleansuccessbooleanlast_rundatetimebw_jobs_cacheidintjob_namevarchar[128]service_idvarchar[64]file_namevarchar[256]datalongbloblast_updatedatetimechecksumvarchar[128]bw_instanceshostnamevarchar[256]portintserver_namevarchar[256]bw_metadataidintis_initializedbooleanfirst_config_savedbooleanautoconf_loadedbooleanscheduler_first_startbooleancustom_configs_changedbooleanexternal_plugins_changedbooleanconfig_changedbooleanintegrationintegrationsversionvarcharbw_plugin_pagesidintplugin_idvarchar[64]template_filelongblobtemplate_checksumvarchar[128]actions_filelongblobactions_checksumvarchar[128]bw_custom_configsidintservice_idvarchar[64]typecustom_config_typesnamevarchar[256]datalongblobchecksumvarchar[128]methodmethods \ No newline at end of file diff --git a/docs/concepts.md b/docs/concepts.md index 9237d4a0f..439ff769a 100644 --- a/docs/concepts.md +++ b/docs/concepts.md @@ -1,7 +1,7 @@ # Concepts
- ![Overwiew](assets/img/concepts.svg){ align=center } + ![Overwiew](assets/img/concepts.svg){ align=center, width="600" }
## Integrations @@ -52,17 +52,19 @@ USE_BROTLI=no ## Multisite mode -The multisite mode is a crucial concept to understand when using BunkerWeb. Because the goal is to protect web applications, our solution is intrinsically linked to the concept of "virtual host" or "vhost" (more info [here](https://en.wikipedia.org/wiki/Virtual_hosting)) which makes it possible to serve multiple web applications from a single (or a cluster of) instance. +Understanding the multisite mode is essential when utilizing BunkerWeb. As our primary focus is safeguarding web applications, our solution is intricately linked to the concept of "virtual hosts" or "vhosts" (more info [here](https://en.wikipedia.org/wiki/Virtual_hosting)). These virtual hosts enable the serving of multiple web applications from a single instance or cluster. -By default, the multisite mode of BunkerWeb is disabled which means that only one web application will be served and all the settings will be applied to it. The typical use case is having a single application to protect : you don't have to worry about the multisite and the default behavior should be the right one for you. +By default, BunkerWeb has the multisite mode disabled. This means that only one web application will be served, and all settings will be applied to it. This setup is ideal when you have a single application to protect, as you don't need to concern yourself with multisite configurations. -When multisite mode is enabled, BunkerWeb serves and protects multiple web applications. Each web application is identified by a unique server name and have its own set of settings. The typical use case is having multiple applications to protect and you want to use a single (or a cluster depending of the integration) instance of BunkerWeb. +However, when the multisite mode is enabled, BunkerWeb becomes capable of serving and protecting multiple web applications. Each web application is identified by a unique server name and has its own set of settings. This mode proves beneficial when you have multiple applications to secure, and you prefer to utilize a single instance (or a cluster) of BunkerWeb. -The multisite mode is controlled by the `MULTISITE` setting which can be set to `yes` (enabled) or `no` (disabled, which is the default). +The activation of the multisite mode is controlled by the `MULTISITE` setting, which can be set to `yes` to enable it or `no` to keep it disabled (which is the default value). -Each setting has a context that defines "where" it can be applied. If the context is global then the setting can't be set per server (or "per site", "per app") but only to the whole configuration. Otherwise, if the context is multisite, the setting can be set globally and per server. Defining a multisite setting to a specific server is done by adding the server name as a prefix of the setting name like `app1.example.com_AUTO_LETS_ENCRYPT` or `app2.example.com_USE_ANTIBOT` for example. When a multisite setting is defined globally (without any server prefix), all the servers will inherit that setting (but can still be overridden if we set the same setting with the server name prefix). +Each setting within BunkerWeb has a specific context that determines where it can be applied. If the context is set to "global," the setting can't be applied per server or site but is instead applied to the entire configuration as a whole. On the other hand, if the context is "multisite," the setting can be applied globally and per server. To define a multisite setting for a specific server, simply add the server name as a prefix to the setting name. For example, `app1.example.com_AUTO_LETS_ENCRYPT` or `app2.example.com_USE_ANTIBOT` are examples of setting names with server name prefixes. When a multisite setting is defined globally without a server prefix, all servers inherit that setting. However, individual servers can still override the setting if the same setting is defined with a server name prefix. -Here is a dummy example of a multisite BunkerWeb configuration : +Understanding the intricacies of multisite mode and its associated settings allows you to tailor BunkerWeb's behavior to suit your specific requirements, ensuring optimal protection for your web applications. + +Here's a dummy example of a multisite BunkerWeb configuration : ```conf MULTISITE=yes @@ -79,48 +81,66 @@ app3.example.com_USE_BAD_BEHAVIOR=no !!! info "Going further" - You will find concrete examples of multisite mode in the [quickstart guide](quickstart-guide.md) of the documentation and the [examples](https://github.com/bunkerity/bunkerweb/tree/v1.5.0/examples) directory of the repository. + You will find concrete examples of multisite mode in the [quickstart guide](quickstart-guide.md) of the documentation and the [examples](https://github.com/bunkerity/bunkerweb/tree/v1.5.1/examples) directory of the repository. ## Custom configurations -Because meeting all the use cases only using the settings is not an option (even with [external plugins](plugins.md)), you can use custom configurations to solve your specific challenges. +To address unique challenges and cater to specific use cases, BunkerWeb offers the flexibility of custom configurations. While the provided settings and [external plugins](plugins.md) cover a wide range of scenarios, there may be situations that require additional customization. -Under the hood, BunkerWeb uses the notorious NGINX web server, that's why you can leverage its configuration system for your specific needs. Custom NGINX configurations can be included in different [contexts](https://docs.nginx.com/nginx/admin-guide/basic-functionality/managing-configuration-files/#contexts) like HTTP or server (all servers and/or specific server block). +BunkerWeb is built on the renowned NGINX web server, which provides a powerful configuration system. This means you can leverage NGINX's configuration capabilities to meet your specific needs. Custom NGINX configurations can be included in various [contexts](https://docs.nginx.com/nginx/admin-guide/basic-functionality/managing-configuration-files/#contexts) such as HTTP or server, allowing you to fine-tune the behavior of BunkerWeb according to your requirements. Whether you need to customize global settings or apply configurations to specific server blocks, BunkerWeb empowers you to optimize its behavior to align perfectly with your use case. -Another core component of BunkerWeb is the ModSecurity Web Application Firewall : you can also use custom configurations to fix some false positives or add custom rules for example. +Another integral component of BunkerWeb is the ModSecurity Web Application Firewall. With custom configurations, you have the flexibility to address false positives or add custom rules to further enhance the protection provided by ModSecurity. These custom configurations allow you to fine-tune the behavior of the firewall and ensure that it aligns with the specific requirements of your web applications. + +By leveraging custom configurations, you unlock a world of possibilities to tailor BunkerWeb's behavior and security measures precisely to your needs. Whether it's adjusting NGINX configurations or fine-tuning ModSecurity, BunkerWeb provides the flexibility to meet your unique challenges effectively. !!! info "Going further" - You will find concrete examples of custom configurations in the [quickstart guide](quickstart-guide.md) of the documentation and the [examples](https://github.com/bunkerity/bunkerweb/tree/v1.5.0/examples) directory of the repository. + You will find concrete examples of custom configurations in the [quickstart guide](quickstart-guide.md) of the documentation and the [examples](https://github.com/bunkerity/bunkerweb/tree/v1.5.1/examples) directory of the repository. ## Database -State of the current configuration of BunkerWeb is stored in a backend database which contains the following data : +BunkerWeb securely stores its current configuration in a backend database, which contains essential data for smooth operation. The following information is stored in the database: -- Settings defined for all the services -- Custom configurations -- BunkerWeb instances -- Metadata about jobs execution -- Cached files +- **Settings for all services**: The database holds the defined settings for all the services provided by BunkerWeb. This ensures that your configurations and preferences are preserved and readily accessible. -Under the hood, when you edit a setting or add a new configuration, everything is stored in the database. We actually support SQLite, MariaDB, MySQL and PostgreSQL as backends. +- **Custom configurations**: Any custom configurations you create are also stored in the backend database. This includes personalized settings and modifications tailored to your specific requirements. -Database configuration is done by using the `DATABASE_URI` setting which respects the following formats : +- **BunkerWeb instances**: Information about BunkerWeb instances, including their setup and relevant details, is stored in the database. This allows for easy management and monitoring of multiple instances if applicable. -- SQLite : `sqlite:///var/lib/bunkerweb/db.sqlite3` -- MariaDB : `mariadb+pymysql://bunkerweb:changeme@bw-db:3306/db` -- MySQL : `mysql+pymysql://bunkerweb:changeme@bw-db:3306/db` -- PostgreSQL : `postgresql://bunkerweb:changeme@bw-db:5432/db` +- **Metadata about job execution**: The database stores metadata related to the execution of various jobs within BunkerWeb. This includes information about scheduled tasks, maintenance processes, and other automated activities. + +- **Cached files**: BunkerWeb utilizes caching mechanisms for improved performance. The database holds cached files, ensuring efficient retrieval and delivery of frequently accessed resources. + +Under the hood, whenever you edit a setting or add a new configuration, BunkerWeb automatically stores the changes in the database, ensuring data persistence and consistency. BunkerWeb supports multiple backend database options, including SQLite, MariaDB, MySQL, and PostgreSQL. + +Configuring the database is straightforward using the `DATABASE_URI` setting, which follows the specified formats for each supported database: + +- **SQLite**: `sqlite:///var/lib/bunkerweb/db.sqlite3` +- **MariaDB**: `mariadb+pymysql://bunkerweb:changeme@bw-db:3306/db` +- **MySQL**: `mysql+pymysql://bunkerweb:changeme@bw-db:3306/db` +- **PostgreSQL**: `postgresql://bunkerweb:changeme@bw-db:5432/db` + +By specifying the appropriate database URI in the configuration, you can seamlessly integrate BunkerWeb with your preferred database backend, ensuring efficient and reliable storage of your configuration data. + +
+ ![Overview](assets/img/bunkerweb_db.svg){ align=center, width="800" } +
Database Schema
+
## Scheduler -To make things automagically work together, a dedicated service called the scheduler is in charge of : +For seamless coordination and automation, BunkerWeb employs a specialized service known as the scheduler. The scheduler plays a vital role in ensuring smooth operation by performing the following tasks: -- Storing the settings and custom configurations inside the database -- Executing various tasks (called jobs) -- Generating a configuration which is understood by BunkerWeb -- Being the intermediary for other services (like web UI or autoconf) +- **Storing settings and custom configurations**: The scheduler is responsible for storing all the settings and custom configurations within the backend database. This centralizes the configuration data, making it easily accessible and manageable. -In other words, the scheduler is the brain of BunkerWeb. +- **Executing various tasks (jobs)**: The scheduler handles the execution of various tasks, referred to as jobs. These jobs encompass a range of activities, such as periodic maintenance, scheduled updates, or any other automated tasks required by BunkerWeb. -When using container-based integrations, the scheduler is executed in its own container. Whereas, for linux-based integrations scheduler is self-contained in the `bunkerweb` service. \ No newline at end of file +- **Generating BunkerWeb configuration**: The scheduler generates a configuration that is readily understood by BunkerWeb. This configuration is derived from the stored settings and custom configurations, ensuring that the entire system operates cohesively. + +- **Acting as an intermediary for other services**: The scheduler acts as an intermediary, facilitating communication and coordination between different components of BunkerWeb. It interfaces with services such as the web UI or autoconf, ensuring a seamless flow of information and data exchange. + +In essence, the scheduler serves as the brain of BunkerWeb, orchestrating various operations and ensuring the smooth functioning of the system. + +Depending on the integration approach, the execution environment of the scheduler may differ. In container-based integrations, the scheduler is executed within its dedicated container, providing isolation and flexibility. On the other hand, for Linux-based integrations, the scheduler is self-contained within the bunkerweb service, simplifying the deployment and management process. + +By employing the scheduler, BunkerWeb streamlines the automation and coordination of essential tasks, enabling efficient and reliable operation of the entire system. \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index 17c64011d..c5014802b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -7,35 +7,56 @@
Make your web services secure by default !
-BunkerWeb is a next-generation and open-source Web Application Firewall (WAF). +Introducing BunkerWeb, the **cutting-edge** and **open-source Web Application Firewall** (WAF) that will revolutionize your web security experience. -Being a full-featured web server (based on [NGINX](https://nginx.org/) under the hood), it will protect your web services to make them "secure by default". BunkerWeb integrates seamlessly into your existing environments ([Linux](integrations.md#linux), [Docker](integrations.md#docker), [Swarm](integrations.md#swarm), [Kubernetes](integrations.md#kubernetes), â€Ļ) and is fully configurable (don't panic, there is an [awesome web UI](web-ui.md) if you don't like the CLI) to meet your own use-cases . In other words, cybersecurity is no more a hassle. +With BunkerWeb, your web services are safeguarded by default, providing you with peace of mind and enhanced protection. Powered by [NGINX](https://nginx.org/), this comprehensive web server combines advanced features seamlessly, ensuring your online assets remain secure. + +BunkerWeb effortlessly integrates into your existing environments, whether it's [Linux](integrations.md#linux), [Docker](integrations.md#docker), [Swarm](integrations.md#swarm), [Kubernetes](integrations.md#kubernetes), or more. Its versatility allows for easy configuration to suit your specific requirements. Don't worry if you prefer a user-friendly interface—BunkerWeb offers an exceptional [web UI](web-ui.md) alongside the command-line interface (CLI), ensuring accessibility for all users. + +Experience the transformation in cybersecurity, where complexities and obstacles are a thing of the past. With BunkerWeb, fortifying your digital assets has never been more delightful and hassle-free. + +Furthermore, BunkerWeb boasts a comprehensive set of primary [security features](security-tuning.md) at its core. However, what sets it apart is its remarkable flexibility through an intuitive [plugin system](plugins.md). This ingenious design empowers you to effortlessly enhance BunkerWeb with additional security measures, ensuring a tailored and robust defense for your web applications. + +By seamlessly integrating new plugins into BunkerWeb, you can customize and expand its capabilities to address specific security requirements unique to your environment. Whether you need to strengthen authentication protocols, bolster threat detection, or implement specialized security measures, BunkerWeb's [plugin system](plugins.md) grants you the freedom to fortify your web infrastructure with ease. + +With BunkerWeb's dynamic [plugin system](plugins.md), security becomes an enjoyable journey of exploration and empowerment. Discover the endless possibilities and create a fortified web environment that perfectly aligns with your needs. -BunkerWeb contains primary [security features](security-tuning.md) as part of the core but can be easily extended with additional ones thanks to a [plugin system](plugins.md)). ## Why BunkerWeb ? -- **Easy integration into existing environments** : support for Linux, Docker, Swarm, Kubernetes, Ansible, Vagrant, ... -- **Highly customizable** : enable, disable and configure features easily to meet your use case -- **Secure by default** : offers out-of-the-box and hassle-free minimal security for your web services -- **Awesome web UI** : keep control of everything more efficiently without the need of the CLI -- **Plugin system** : extend BunkerWeb to meet your own use-cases -- **Free as in "freedom"** : licensed under the free [AGPLv3 license](https://www.gnu.org/licenses/agpl-3.0.en.html) +- **Easy integration into existing environments** : Seamlessly integrate BunkerWeb into various environments such as Linux, Docker, Swarm, Kubernetes, Ansible, Vagrant, and more. Enjoy a smooth transition and hassle-free implementation. + +- **Highly customizable** : Tailor BunkerWeb to your specific requirements with ease. Enable, disable, and configure features effortlessly, allowing you to customize the security settings according to your unique use case. + +- **Secure by default** : BunkerWeb provides out-of-the-box, hassle-free minimal security for your web services. Experience peace of mind and enhanced protection right from the start. + +- **Awesome web UI** : Take control of BunkerWeb more efficiently with the exceptional web user interface (UI). Navigate settings and configurations effortlessly through a user-friendly graphical interface, eliminating the need for the command-line interface (CLI). + +- **Plugin system** : Extend the capabilities of BunkerWeb to meet your own use cases. Seamlessly integrate additional security measures and customize the functionality of BunkerWeb according to your specific requirements. + +- **Free as in "freedom"** : BunkerWeb is licensed under the free [AGPLv3 license](https://www.gnu.org/licenses/agpl-3.0.en.html), embracing the principles of freedom and openness. Enjoy the freedom to use, modify, and distribute the software, backed by a supportive community. ## Security features -A non-exhaustive list of security features : +Explore the impressive array of security features offered by BunkerWeb. While not exhaustive, here are some notable highlights: -- **HTTPS** support with transparent **Let's Encrypt** automation -- **State-of-the-art web security** : HTTP security headers, prevent leaks, TLS hardening, ... -- Integrated **ModSecurity WAF** with the **OWASP Core Rule Set** -- **Automatic ban** of strange behaviors based on HTTP status code -- Apply **connections and requests limit** for clients -- **Block bots** by asking them to solve a **challenge** (e.g. : cookie, javascript, captcha, hCaptcha or reCAPTCHA) -- **Block known bad IPs** with external blacklists and DNSBL -- And much more ... +- **HTTPS** support with transparent **Let's Encrypt** automation : Easily secure your web services with automated Let's Encrypt integration, ensuring encrypted communication between clients and your server. -Learn more about the core security features in the [security tuning](security-tuning.md) section of the documentation. +- **State-of-the-art web security** : Benefit from cutting-edge web security measures, including comprehensive HTTP security headers, prevention of data leaks, and TLS hardening techniques. + +- Integrated **ModSecurity WAF** with the **OWASP Core Rule Set** : Enjoy enhanced protection against web application attacks with the integration of ModSecurity, fortified by the renowned OWASP Core Rule Set. + +- **Automatic ban** of strange behaviors based on HTTP status code : BunkerWeb intelligently identifies and blocks suspicious activities by automatically banning behaviors that trigger abnormal HTTP status codes. + +- Apply **connections and requests limit** for clients : Set limits on the number of connections and requests from clients, preventing resource exhaustion and ensuring fair usage of server resources. + +- **Block bots** with **challenge-based verification** : Keep malicious bots at bay by challenging them to solve puzzles such as cookies, JavaScript tests, captcha, hCaptcha, reCAPTCHA or Turnstile, effectively blocking unauthorized access. + +- **Block known bad IPs** with external blacklists and DNSBL : Utilize external blacklists and DNS-based blackhole lists (DNSBL) to proactively block known malicious IP addresses, bolstering your defense against potential threats. + +- **And much more...** : BunkerWeb is packed with a plethora of additional security features that go beyond this list, providing you with comprehensive protection and peace of mind. + +To delve deeper into the core security features, we invite you to explore the [security tuning](security-tuning.md) section of the documentation. Discover how BunkerWeb empowers you to fine-tune and optimize security measures according to your specific needs. ## Demo diff --git a/docs/integrations.md b/docs/integrations.md index d640e80bb..6efa1c22d 100644 --- a/docs/integrations.md +++ b/docs/integrations.md @@ -7,15 +7,28 @@
Docker integration
-Using BunkerWeb as a [Docker](https://www.docker.com/) container is a quick and easy way to test and use it as long as you are familiar with the Docker technology. +Utilizing BunkerWeb as a [Docker](https://www.docker.com/) container offers a convenient and straightforward approach for testing and utilizing the solution, particularly if you are already familiar with Docker technology. -We provide ready-to-use prebuilt images for x64, x86 armv8 and armv7 architectures on [Docker Hub](https://hub.docker.com/r/bunkerity/bunkerweb) : +To facilitate your Docker deployment, we provide readily available prebuilt images on [Docker Hub](https://hub.docker.com/r/bunkerity/bunkerweb), supporting multiple architectures. These prebuilt images are optimized and prepared for use on the following architectures: + +- x64 (64-bit) +- x86 +- armv8 (ARM 64-bit) +- armv7 (ARM 32-bit) + +By accessing these prebuilt images from Docker Hub, you can quickly pull and run BunkerWeb within your Docker environment, eliminating the need for extensive configuration or setup processes. This streamlined approach allows you to focus on leveraging the capabilities of BunkerWeb without unnecessary complexities. + +Whether you're conducting tests, developing applications, or deploying BunkerWeb in production, the Docker containerization option provides flexibility and ease of use. Embracing this method empowers you to take full advantage of BunkerWeb's features while leveraging the benefits of Docker technology. ```shell -docker pull bunkerity/bunkerweb:1.5.0 +docker pull bunkerity/bunkerweb:1.5.1 ``` -Alternatively, you can build the Docker image directly from the [source](https://github.com/bunkerity/bunkerweb) (and get a coffee ☕ because it may take a long time depending on your hardware) : +Alternatively, if you prefer a more hands-on approach, you have the option to build the Docker image directly from the [source](https://github.com/bunkerity/bunkerweb). Building the image from source gives you greater control and customization over the deployment process. However, please note that this method may take some time to complete, depending on your hardware configuration. + +While the image is being built, you can take a moment to relax and enjoy a cup of coffee ☕, as the process may require some patience. Once the image is successfully built, you can proceed to deploy and utilize BunkerWeb within your Docker environment. This method allows you to tailor the image to your specific requirements and ensures a more personalized deployment of BunkerWeb. + +So, whether you choose to use the ready-to-use prebuilt images or embark on the journey of building the image from source, BunkerWeb in Docker provides you with the flexibility and options to seamlessly integrate it into your environment. ```shell git clone https://github.com/bunkerity/bunkerweb.git && \ @@ -29,8 +42,16 @@ Docker integration key concepts are : - **Scheduler** container to store configuration and execute jobs - **Networks** to expose ports for clients and connect to upstream web services +When integrating BunkerWeb with Docker, there are key concepts to keep in mind, ensuring a smooth and efficient deployment: + +- **Environment variables**: BunkerWeb can be easily configured using environment variables. These variables allow you to customize various aspects of BunkerWeb's behavior, such as network settings, security options, and other parameters. + +- **Scheduler container**: To effectively manage the configuration and execution of jobs, BunkerWeb utilizes a dedicated container called the [scheduler](concepts.md#scheduler). + +- **Networks**: Docker networks play a vital role in the integration of BunkerWeb. These networks serve two main purposes: exposing ports to clients and connecting to upstream web services. By exposing ports, BunkerWeb can accept incoming requests from clients, allowing them to access the protected web services. Additionally, by connecting to upstream web services, BunkerWeb can efficiently route and manage the traffic, providing enhanced security and performance. + !!! info "Database backend" - Please note that we assume you are using SQLite as database backend (which is the default for the `DATABASE_URI` setting). Other backends for this integration are still possible if you want to : see docker-compose files in the [misc/integrations folder](https://github.com/bunkerity/bunkerweb/tree/v1.5.0/misc/integrations) folder of the repostiory for more information. + Please be aware that our instructions assume you are using SQLite as the default database backend, as configured by the `DATABASE_URI` setting. However, we understand that you may prefer to utilize alternative backends for your Docker integration. If that is the case, rest assured that other database backends are still possible. See docker-compose files in the [misc/integrations folder](https://github.com/bunkerity/bunkerweb/tree/v1.5.1/misc/integrations) folder of the repository for more information. ### Environment variables @@ -40,7 +61,7 @@ Settings are passed to BunkerWeb using Docker environment variables : ... services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 labels: - "bunkerweb.INSTANCE" environment: @@ -59,7 +80,7 @@ Please note that the `bunkerweb.INSTANCE` is mandatory to make sure the schedule The [scheduler](concepts.md#scheduler) is executed in its own container which is also available on Docker Hub : ```shell -docker pull bunkerity/bunkerweb-scheduler:1.5.0 +docker pull bunkerity/bunkerweb-scheduler:1.5.1 ``` Alternatively, you can build the Docker image directly from the [source](https://github.com/bunkerity/bunkerweb) (less coffee ☕ needed than BunkerWeb image) : @@ -76,7 +97,7 @@ A volume is needed to store the SQLite database that will be used by the schedul ... services: mybunker: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 volumes: - bw-data:/data ... @@ -85,7 +106,6 @@ volumes: ``` !!! warning "Using local folder for persistent data" - The scheduler runs as an **unprivileged user with UID 101 and GID 101** inside the container. The reason behind this is security : in case a vulnerability is exploited, the attacker won't have full root (UID/GID 0) privileges. But there is a downside : if you use a **local folder for the persistent data**, you will need to **set the correct permissions** so the unprivileged user can write data to it. Something like that should do the trick : @@ -127,10 +147,11 @@ volumes: When using Docker-based integrations, the scheduler will need to access the Docker API to get things working which is defined using the `DOCKER_HOST` environment variable. !!! warning "Docker API access and security" + Due to Docker's limitations in supporting fine-grained authorizations, it's important to be aware of the potential security risks associated with accessing the API directly. Accessing the Docker API can pose a threat, as an attacker with API access can potentially obtain root privileges on the host machine. For more detailed information on this topic, we encourage you to refer to the provided link ([here](https://blog.quarkslab.com/why-is-exposing-the-docker-socket-a-really-bad-idea.html)). - Since Docker doesn't support fine-grained authorizations, accessing the API poses a security risk. An attacker with access to the API can easily gain root privileges on the host machine (more info [here](https://blog.quarkslab.com/why-is-exposing-the-docker-socket-a-really-bad-idea.html)). + To mitigate these risks, we strongly advise against directly mounting the socket file located at `/var/run/docker.sock` within the BunkerWeb container. Instead, we recommend employing an alternative approach that enhances security. One such approach involves using a "proxy" container, such as `tecnativa/docker-socket-proxy`, which acts as an intermediary and allows only necessary API calls. - We strongly recommend not to mount the socket file usually located at `/var/run/docker.sock` directly in the container. An alternative, which is described here, is to use a "proxy" container like [tecnativa/docker-socket-proxy](https://github.com/Tecnativa/docker-socket-proxy) that will allow only the necessary API calls. + By adopting this proxy container strategy, you can establish a more secure communication channel with the Docker API, minimizing the potential attack surface and enhancing overall system security. You will need to create the Docker API proxy container, mount the socket and set the `DOCKER_HOST` environment variable to use the Docker API proxy : @@ -138,16 +159,17 @@ You will need to create the Docker API proxy container, mount the socket and set ... services: bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 env: - DOCKER_HOST=tcp://bw-docker:2375 ... bw-docker: - image: tecnativa/docker-socket-proxy + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock environment: - CONTAINERS=1 + - LOG_LEVEL=warning ... ``` @@ -179,13 +201,13 @@ For defense in depth purposes, we strongly recommend to create at least three di - `bw-universe` : for BunkerWeb and scheduler - `bw-docker` : for scheduler and the Docker API proxy -The scheduler needs to contact the API of BunkerWeb and for obvious security reason BunkerWeb needs to check if the caller is authorized to make API calls. The `API_WHITELIST_IP` setting lets you choose allowed IP addresses and subnets, usage of a static subnet for the `bw-universe` is strongly advised : +To secure the communication between the scheduler and BunkerWeb API, it is important to authorize API calls. You can use the `API_WHITELIST_IP` setting to specify allowed IP addresses and subnets. It is strongly recommended to use a static subnet for the `bw-universe` network to enhance security. By implementing these measures, you can ensure that only authorized sources can access the BunkerWeb API, reducing the risk of unauthorized access or malicious activities: ```yaml ... services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -194,13 +216,13 @@ services: - bw-universe ... bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 networks: - bw-universe - bw-docker ... bw-docker: - image: tecnativa/docker-socket-proxy + image: tecnativa/docker-socket-proxy:nightly networks: - bw-docker ... @@ -224,7 +246,7 @@ version: "3.5" services: bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -238,7 +260,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - bunkerweb - bw-docker @@ -251,11 +273,12 @@ services: - bw-docker bw-docker: - image: tecnativa/docker-socket-proxy + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker @@ -285,24 +308,28 @@ networks: !!! info "Docker integration" The Docker autoconf integration is an "evolution" of the Docker one. Please read the [Docker integration section](#docker) first if needed. -The downside of using environment variables is that the container needs to be recreated each time there is an update which is not very convenient. To counter that issue, you can use another image called **autoconf** which will listen for Docker events and automatically reconfigure BunkerWeb in real-time without recreating the container. +An alternative approach is available to address the inconvenience of recreating the container every time there is an update. By utilizing another image called **autoconf**, you can automate the real-time reconfiguration of BunkerWeb without the need for container recreation. -Instead of defining environment variables for the BunkerWeb container, you simply add **labels** to your web applications containers and the **autoconf** will "automagically" take care of the rest. +To leverage this functionality, instead of defining environment variables for the BunkerWeb container, you can add **labels** to your web application containers. The **autoconf** image will then listen for Docker events and seamlessly handle the configuration updates for BunkerWeb. + +This "automagical" process simplifies the management of BunkerWeb configurations. By adding labels to your web application containers, you can delegate the reconfiguration tasks to **autoconf** without the manual intervention of container recreation. This streamlines the update process and enhances convenience. + +By adopting this approach, you can enjoy real-time reconfiguration of BunkerWeb without the hassle of container recreation, making it more efficient and user-friendly. !!! info "Multisite mode" The Docker autoconf integration implies the use of **multisite mode**. Please refer to the [multisite section](concepts.md#multisite-mode) of the documentation for more information. !!! info "Database backend" - Please note that we assume you are using MariaDB as database backend (which is defined using the `DATABASE_URI` setting). Other backends for this integration are still possible if you want : see docker-compose files in the [misc/integrations folder](https://github.com/bunkerity/bunkerweb/tree/v1.5.0/misc/integrations) folder of the repostiory for more information. + Please be aware that our instructions assume you are using MariaDB as the default database backend, as configured by the `DATABASE_URI` setting. However, we understand that you may prefer to utilize alternative backends for your Docker integration. If that is the case, rest assured that other database backends are still possible. See docker-compose files in the [misc/integrations folder](https://github.com/bunkerity/bunkerweb/tree/v1.5.1/misc/integrations) folder of the repository for more information. -Another container, named `bw-autoconf` for example, containing the autoconf service must be added to the stack. Since two services will generate the configuration for BunkerWeb, a "real" database backend (in other words, not SQLite) also needs to be added : +To enable automated configuration updates, include an additional container called `bw-autoconf` in the stack. This container hosts the autoconf service, which manages dynamic configuration changes for BunkerWeb. To support this functionality, use a dedicated "real" database backend (e.g., MariaDB, MySQL, or PostgreSQL) for synchronized configuration storage. By integrating `bw-autoconf` and a suitable database backend, you establish the infrastructure for seamless automated configuration management in BunkerWeb. ```yaml version: "3.5" services: bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -319,7 +346,7 @@ services: - bw-services bw-autoconf: - image: bunkerity/bunkerweb-autoconf:1.5.0 + image: bunkerity/bunkerweb-autoconf:1.5.1 depends_on: - bunkerweb - bw-docker @@ -332,7 +359,7 @@ services: - bw-docker bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - bunkerweb - bw-docker @@ -345,11 +372,12 @@ services: - bw-docker bw-docker: - image: tecnativa/docker-socket-proxy + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker @@ -381,6 +409,9 @@ networks: name: bw-docker ``` +!!! info "Database in the `bw-docker` network" + The database container is intentionally not included in the `bw-universe` network. It is used by the `bw-autoconf` and `bw-scheduler` containers rather than directly by BunkerWeb. Therefore, the database container is part of the `bw-docker` network, which enhances security by making external access to the database more challenging. This deliberate design choice helps safeguard the database and strengthens the overall security perspective of the system. + !!! warning "Using Docker in rootless mode" If you are using [Docker in rootless mode](https://docs.docker.com/engine/security/rootless), you will need to replace the mount of the docker socket with the following value : `$XDG_RUNTIME_DIR/docker.sock:/var/run/docker.sock:ro`. @@ -416,18 +447,20 @@ networks: !!! info "Docker autoconf" The Swarm integration is similar to the Docker autoconf one (but with services instead of containers). Please read the [Docker autoconf integration section](#docker-autoconf) first if needed. -To automatically configure BunkerWeb instances, a special service called **autoconf** needs to have access to the Docker API. That service will listen for Docker Swarm events like service creation or deletion and automatically configure the **BunkerWeb instances** in real-time without downtime. It also monitors other Swarm objects like [configs](https://docs.docker.com/engine/swarm/configs/) for custom configurations. +To enable automatic configuration of BunkerWeb instances, the **autoconf** service requires access to the Docker API. This service listens for Docker Swarm events, such as service creation or deletion, and seamlessly configures the **BunkerWeb instances** in real-time without any downtime. It also monitors other Swarm objects, such as [configs](https://docs.docker.com/engine/swarm/configs/), for custom configurations. -Like the [Docker autoconf integration](#docker-autoconf), configuration for web services is defined by using labels starting with the special **bunkerweb.** prefix. +Similar to the [Docker autoconf integration](#docker-autoconf), configuration for web services is defined using labels that start with the **bunkerweb** prefix. -The recommended setup is to schedule the **BunkerWeb service** as a **global service** on all nodes and the **autoconf, scheduler and Docker API proxy services** as **single replicated services**. Please note that the **Docker API proxy service** needs to be scheduled on a manager node unless you configure it to use a remote API (which is not covered in the documentation). +For an optimal setup, it is recommended to schedule the **BunkerWeb service** as a ***global service*** on all nodes, while the **autoconf, scheduler, and Docker API proxy services** should be scheduled as ***single replicated services***. Please note that the Docker API proxy service needs to be scheduled on a manager node unless you configure it to use a remote API (which is not covered in the documentation). -Since we have multiple instances of BunkerWeb running, a shared data store implemented as a [Redis](https://redis.io/) service must be created : the instances will use it to cache and share data. You will find more information about the Redis settings [here](settings.md#redis) +Since multiple instances of BunkerWeb are running, a shared data store implemented as a [Redis](https://redis.io/) service must be created. These instances will utilize the Redis service to cache and share data. Further details regarding the Redis settings can be found [here](settings.md#redis). -Using a shared folder or a specific driver for the database volume is left as an exercise for the reader (and depends on your own use-case). +As for the database volume, the documentation does not specify a specific approach. Choosing either a shared folder or a specific driver for the database volume is dependent on your unique use-case and is left as an exercise for the reader. !!! info "Database backend" - Please note that we assume you are using MariaDB as database backend (which is defined using the `DATABASE_URI` setting). Other backends for this integration are still possible if you want : see docker-compose files in the [misc/integrations folder](https://github.com/bunkerity/bunkerweb/tree/v1.5.0/misc/integrations) folder of the repostiory for more information. Clustered database backends setup are out-of-the-scope of this documentation. + Please be aware that our instructions assume you are using MariaDB as the default database backend, as configured by the `DATABASE_URI` setting. However, we understand that you may prefer to utilize alternative backends for your Docker integration. If that is the case, rest assured that other database backends are still possible. See docker-compose files in the [misc/integrations folder](https://github.com/bunkerity/bunkerweb/tree/v1.5.1/misc/integrations) folder of the repository for more information. + + Clustered database backends setup are out-of-the-scope of this documentation. Here is the stack boilerplate that you can deploy using `docker stack deploy` : @@ -436,7 +469,7 @@ version: "3.5" services: bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - published: 80 target: 8080 @@ -466,7 +499,7 @@ services: - "bunkerweb.INSTANCE" bw-autoconf: - image: bunkerity/bunkerweb-autoconf:1.5.0 + image: bunkerity/bunkerweb-autoconf:1.5.1 environment: - SWARM_MODE=yes - DOCKER_HOST=tcp://bw-docker:2375 @@ -480,7 +513,7 @@ services: - "node.role == worker" bw-docker: - image: tecnativa/docker-socket-proxy + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: @@ -489,6 +522,7 @@ services: - SERVICES=1 - SWARM=1 - TASKS=1 + - LOG_LEVEL=warning networks: - bw-docker deploy: @@ -497,7 +531,7 @@ services: - "node.role == manager" bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 environment: - SWARM_MODE=yes - DOCKER_HOST=tcp://bw-docker:2375 @@ -556,7 +590,8 @@ networks: attachable: true ``` -Please note that the `SWARM_MODE=yes` environment variable is mandatory when using the Swarm integration. +!!! info "Swarm mandatory setting" + Please note that the `SWARM_MODE=yes` environment variable is mandatory when using the Swarm integration. Once the BunkerWeb Swarm stack is set up and running (see autoconf and scheduler logs for more information), you will be able to deploy web applications in the cluster and use labels to dynamically configure BunkerWeb : @@ -589,20 +624,22 @@ networks:
Kubernetes integration
-The autoconf acts as an [Ingress controller](https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/) and will configure the BunkerWeb instances according to the [Ingress resources](https://kubernetes.io/docs/concepts/services-networking/ingress/). It also monitors other Kubernetes objects like [ConfigMap](https://kubernetes.io/docs/concepts/configuration/configmap/) for custom configurations. +To automate the configuration of BunkerWeb instances in a Kubernetes environment, the autoconf service serves as an [Ingress controller](https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/). It configures the BunkerWeb instances based on [Ingress resources](https://kubernetes.io/docs/concepts/services-networking/ingress/) and also monitors other Kubernetes objects, such as [ConfigMap](https://kubernetes.io/docs/concepts/configuration/configmap/), for custom configurations. -The recommended setup is to define **BunkerWeb** as a **[DaemonSet](https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/)** which will create a pod on all nodes and the **autoconf and scheduler** as **single replicated [Deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/)**. +For an optimal setup, it is recommended to define BunkerWeb as a **[DaemonSet](https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/)**, which ensures that a pod is created on all nodes, while the **autoconf and scheduler** are defined as **single replicated [Deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/)**. -Since we have multiple instances of BunkerWeb running, a shared data store implemented as a [Redis](https://redis.io/) service must be created : the instances will use it to cache and share data. You will find more information about the Redis settings [here](settings.md#redis) +Given the presence of multiple BunkerWeb instances, it is necessary to establish a shared data store implemented as a [Redis](https://redis.io/) service. This Redis service will be utilized by the instances to cache and share data among themselves. Further information about the Redis settings can be found [here](settings.md#redis). !!! info "Database backend" - Please note that we assume you are using MariaDB as database backend (which is defined using the `DATABASE_URI` setting). Other backends for this integration are still possible if you want : see yaml files in the [misc/integrations folder](https://github.com/bunkerity/bunkerweb/tree/v1.5.0/misc/integrations) folder of the repostiory for more information. Clustered database backends setup are out-of-the-scope of this documentation. + Please be aware that our instructions assume you are using MariaDB as the default database backend, as configured by the `DATABASE_URI` setting. However, we understand that you may prefer to utilize alternative backends for your Docker integration. If that is the case, rest assured that other database backends are still possible. See docker-compose files in the [misc/integrations folder](https://github.com/bunkerity/bunkerweb/tree/v1.5.1/misc/integrations) folder of the repository for more information. + + Clustered database backends setup are out-of-the-scope of this documentation. -Please note that both scheduler and autoconf services needs to access the Kubernetes API. The recommended way of doing it is using [RBAC authorization](https://kubernetes.io/docs/reference/access-authn-authz/rbac/). +Please ensure that both the scheduler and autoconf services have access to the Kubernetes API. It is recommended to utilize [RBAC authorization](https://kubernetes.io/docs/reference/access-authn-authz/rbac/) for this purpose. -Another important thing is the `KUBERNETES_MODE=yes` environment variable which is mandatory when using the Kubernetes integration. +Additionally, it is crucial to set the `KUBERNETES_MODE` environment variable to `yes` when utilizing the Kubernetes integration. This variable is mandatory for proper functionality. -Here is the yaml boilerplate you can use as a base : +To assist you, here is a YAML boilerplate that can serve as a foundation for your configuration: ```yaml apiVersion: rbac.authorization.k8s.io/v1 @@ -655,7 +692,7 @@ spec: containers: # using bunkerweb as name is mandatory - name: bunkerweb - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 imagePullPolicy: Always securityContext: runAsUser: 101 @@ -725,7 +762,7 @@ spec: serviceAccountName: sa-bunkerweb containers: - name: bunkerweb-controller - image: bunkerity/bunkerweb-autoconf:1.5.0 + image: bunkerity/bunkerweb-autoconf:1.5.1 imagePullPolicy: Always env: - name: KUBERNETES_MODE @@ -752,7 +789,7 @@ spec: serviceAccountName: sa-bunkerweb containers: - name: bunkerweb-scheduler - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 imagePullPolicy: Always env: - name: KUBERNETES_MODE @@ -867,7 +904,9 @@ spec: storage: 5Gi ``` -Once the BunkerWeb Kubernetes stack is set up and running (see autoconf logs for more information), you will be able to deploy web applications in the cluster and declare your Ingress resource. Please note that [settings](settings.md) need to be set as annotations for the Ingress resource with the special value **bunkerweb.io** for the domain part : +Once the BunkerWeb Kubernetes stack is successfully set up and operational (refer to the autoconf logs for detailed information), you can proceed with deploying web applications within the cluster and declaring your Ingress resource. + +It is important to note that the BunkerWeb settings need to be specified as annotations for the Ingress resource. For the domain part, please use the special value "**bunkerweb.io**". By including the appropriate annotations, you can configure BunkerWeb accordingly for the Ingress resource. ```yaml apiVersion: networking.k8s.io/v1 @@ -899,16 +938,16 @@ spec:
Linux integration
-List of supported Linux distros (amd64/x86_64 and arm64/aarch64 architectures) : +Supported Linux distributions for BunkerWeb (amd64/x86_64 and arm64/aarch64 architectures) include: - Debian 11 "Bullseye" - Ubuntu 22.04 "Jammy" - Fedora 38 -- RedHat Enterprise Linux (RHEL) 8.7 +- Red Hat Enterprise Linux (RHEL) 8.7 -Please note that you will need to **install NGINX 1.24.0 before BunkerWeb**. For all distros, except Fedora, using prebuilt packages from [official NGINX repository](https://nginx.org/en/linux_packages.html) is mandatory. Compiling NGINX from source or using packages from different repositories won't work with the official prebuilt packages of BunkerWeb but you can build it from source. +Please ensure that you have **NGINX 1.24.0 installed before installing BunkerWeb**. For all distributions, except Fedora, it is mandatory to use prebuilt packages from the [official NGINX repository](https://nginx.org/en/linux_packages.html). Compiling NGINX from source or using packages from different repositories will not work with the official prebuilt packages of BunkerWeb. However, you have the option to build BunkerWeb from source. -Repositories of Linux packages for BunkerWeb are available on [PackageCloud](https://packagecloud.io/bunkerity/bunkerweb). They provide a bash script to add and trust the repository automatically (but you can also follow the [manual installation](https://packagecloud.io/bunkerity/bunkerweb/install) instructions if you prefer). +To simplify the installation process, Linux package repositories for BunkerWeb are available on [PackageCloud](https://packagecloud.io/bunkerity/bunkerweb). They provide a bash script that automatically adds and trusts the repository. You can follow the provided script for automatic setup, or opt for [manual installation](https://packagecloud.io/bunkerity/bunkerweb/install) instructions if you prefer. === "Debian" @@ -930,12 +969,12 @@ Repositories of Linux packages for BunkerWeb are available on [PackageCloud](htt sudo apt install -y nginx=1.24.0-1~$(lsb_release -cs) ``` - And finally install BunkerWeb 1.5.0 : + And finally install BunkerWeb 1.5.1 : ```shell curl -s https://packagecloud.io/install/repositories/bunkerity/bunkerweb/script.deb.sh | sudo bash && \ sudo apt update && \ - sudo apt install -y bunkerweb=1.5.0 + sudo apt install -y bunkerweb=1.5.1 ``` To prevent upgrading NGINX and/or BunkerWeb packages when executing `apt upgrade`, you can use the following command : @@ -964,12 +1003,12 @@ Repositories of Linux packages for BunkerWeb are available on [PackageCloud](htt sudo apt install -y nginx=1.24.0-1~jammy ``` - And finally install BunkerWeb 1.5.0 : + And finally install BunkerWeb 1.5.1 : ```shell curl -s https://packagecloud.io/install/repositories/bunkerity/bunkerweb/script.deb.sh | sudo bash && \ sudo apt update && \ - sudo apt install -y bunkerweb=1.5.0 + sudo apt install -y bunkerweb=1.5.1 ``` To prevent upgrading NGINX and/or BunkerWeb packages when executing `apt upgrade`, you can use the following command : @@ -986,14 +1025,14 @@ Repositories of Linux packages for BunkerWeb are available on [PackageCloud](htt sudo dnf install -y nginx-1.24.0 ``` - And finally install BunkerWeb 1.5.0 : + And finally install BunkerWeb 1.5.1 : ```shell curl -s https://packagecloud.io/install/repositories/bunkerity/bunkerweb/script.rpm.sh | \ sed 's/yum install -y pygpgme --disablerepo='\''bunkerity_bunkerweb'\''/yum install -y python-gnupg/g' | \ sed 's/pypgpme_check=`rpm -qa | grep -qw pygpgme`/python-gnupg_check=`rpm -qa | grep -qw python-gnupg`/g' | sudo bash && \ sudo dnf makecache && \ - sudo dnf install -y bunkerweb-1.5.0 + sudo dnf install -y bunkerweb-1.5.1 ``` To prevent upgrading NGINX and/or BunkerWeb packages when executing `dnf upgrade`, you can use the following command : @@ -1030,13 +1069,13 @@ Repositories of Linux packages for BunkerWeb are available on [PackageCloud](htt ```shell sudo dnf install nginx-1.24.0 ``` - And finally install BunkerWeb 1.5.0 : + And finally install BunkerWeb 1.5.1 : ```shell dnf install -y epel-release && \ curl -s https://packagecloud.io/install/repositories/bunkerity/bunkerweb/script.rpm.sh | sudo bash && \ sudo dnf check-update && \ - sudo dnf install -y bunkerweb-1.5.0 + sudo dnf install -y bunkerweb-1.5.1 ``` To prevent upgrading NGINX and/or BunkerWeb packages when executing `dnf upgrade`, you can use the following command : @@ -1046,103 +1085,6 @@ Repositories of Linux packages for BunkerWeb are available on [PackageCloud](htt sudo dnf versionlock add bunkerweb ``` - - The configuration of BunkerWeb is done by editing the `/etc/bunkerweb/variables.env` file : ```conf @@ -1165,61 +1107,63 @@ BunkerWeb is managed using systemctl :
Ansible integration
-List of supported Linux distros (amd64/x86_64 and arm64/aarch64 architectures) : +Supported Linux distributions for BunkerWeb (amd64/x86_64 and arm64/aarch64 architectures) include: - Debian 11 "Bullseye" - Ubuntu 22.04 "Jammy" - Fedora 38 -- RedHat Enterprise Linux (RHEL) 8.7 +- Red Hat Enterprise Linux (RHEL) 8.7 -[Ansible](https://docs.ansible.com/ansible/latest/index.html) is an IT automation tool. It can configure systems, deploy software, and orchestrate more advanced IT tasks such as continuous deployments or zero downtime rolling updates. +To simplify the deployment and configuration process, [Ansible](https://docs.ansible.com/ansible/latest/index.html) can be used as an IT automation tool. Ansible enables you to configure systems, deploy software, and perform advanced IT tasks such as continuous deployments or zero downtime rolling updates. -A specific BunkerWeb Ansible role is available on [Ansible Galaxy](https://galaxy.ansible.com/bunkerity/bunkerweb). +For BunkerWeb, there is a dedicated Ansible role available on [Ansible Galaxy](https://galaxy.ansible.com/bunkerity/bunkerweb). -First of all, download the role from ansible-galaxy : -```shell -ansible-galaxy install bunkerity.bunkerweb -``` +To proceed with the BunkerWeb Ansible role setup, follow these steps: -Next, create an inventory by adding the IP adress or FQDN of one or more remote systems, either in `/etc/ansible/hosts` or in your own playbook `inventory.yml` : -```toml -[mybunkers] -192.0.2.50 -192.0.2.51 -192.0.2.52 -``` +1. Begin by creating an inventory file that lists the IP addresses or FQDNs of the remote systems you want to manage. You can either add this information to the `/etc/ansible/hosts` file or create a separate inventory file such as `inventory.yml`. Here's an example using a TOML format: -The next step we're going to set up is the SSH connection so Ansible can connect to the managed nodes. Add your public SSH keys to the `authorized_keys` file on each remote system and ensure you can successfully connect. + ```toml + [mybunkers] + 192.0.2.50 + 192.0.2.51 + 192.0.2.52 + ``` -In order to use the role, we will create the playbook file named `playbook.yml` for example : -```yaml ---- -- hosts: all - become: true - roles: - - bunkerity.bunkerweb -``` +2. Next, establish SSH connections to the managed nodes by adding your public SSH keys to the `authorized_keys` file on each remote system. Verify that you can successfully connect to the nodes using SSH. -Run the playbook : -```shell -ansible-playbook -i inventory.yml playbook.yml -``` +3. Create a playbook file, such as `playbook.yml`, which will define the desired configuration using the BunkerWeb Ansible role. Here's an example playbook configuration: -Configuration of BunkerWeb is done by using specific role variables : + ```yaml + --- + - hosts: all + become: true + roles: + - bunkerity.bunkerweb + ``` -| Name | Type | Description | Default value | -|:-----:|:-----:|--------------|----------------| -| `bunkerweb_version` | string | Version of BunkerWeb to install. | `1.5.0` | -| `nginx_version` | string | Version of NGINX to install. | `1.24.0` | -| `freeze_versions` | boolean | Prevent upgrade of BunkerWeb and NGINX when performing packages upgrades. | `true` | -| `variables_env` | string | Path of the variables.env file to configure BunkerWeb. | `files/variables.env` | -| `enable_ui` | boolean | Activate the web UI. | `false` | -| `custom_ui` | string | Path of the ui.env file to configure the web UI. | `files/ui.env` | -| `custom_configs_path` | Dictionary | Each entry is a path of the folder containing custom configurations. Keys are the type of custom configs : `http`, `server-http`, `modsec`, `modsec-crs` and `default-server-http` | empty values | -| `custom_www` | string | Path of the www directory to upload. | empty value | -| `custom_plugins` | string | Path of the plugins directory to upload. | empty value | -| `custom_www_owner` | string | Default owner for www files and folders. | `nginx` | -| `custom_www_group` | string | Default group for www files and folders. | `nginx` | +4. Execute the playbook using the `ansible-playbook` command, providing the inventory file and the playbook file as arguments. For example: + + ```shell + ansible-playbook -i inventory.yml playbook.yml + ``` + +By running the playbook, Ansible will apply the BunkerWeb role to all the hosts specified in the inventory, setting up the desired configuration. + +the configuration of BunkerWeb is done by using specific role variables : + +| Name | Type | Description | Default value | +| :-------------------: | :--------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- | +| `bunkerweb_version` | string | Version of BunkerWeb to install. | `1.5.1` | +| `nginx_version` | string | Version of NGINX to install. | `1.24.0` | +| `freeze_versions` | boolean | Prevent upgrade of BunkerWeb and NGINX when performing packages upgrades. | `true` | +| `variables_env` | string | Path of the variables.env file to configure BunkerWeb. | `files/variables.env` | +| `enable_ui` | boolean | Activate the web UI. | `false` | +| `custom_ui` | string | Path of the ui.env file to configure the web UI. | `files/ui.env` | +| `custom_configs_path` | Dictionary | Each entry is a path of the folder containing custom configurations. Keys are the type of custom configs : `http`, `server-http`, `modsec`, `modsec-crs` and `default-server-http` | empty values | +| `custom_www` | string | Path of the www directory to upload. | empty value | +| `custom_plugins` | string | Path of the plugins directory to upload. | empty value | +| `custom_www_owner` | string | Default owner for www files and folders. | `nginx` | +| `custom_www_group` | string | Default group for www files and folders. | `nginx` | ## Vagrant @@ -1229,24 +1173,22 @@ Configuration of BunkerWeb is done by using specific role variables :
BunkerWeb integration with Vagrant
--> + List of supported providers : -- vmware_desktop - virtualbox - libvirt -**_Note on Supported Base Images_** - -Please be aware that the provided Vagrant boxes are based **exclusively on Ubuntu 22.04 "Jammy"**. While BunkerWeb supports other Linux distributions, the Vagrant setup currently only supports Ubuntu 22.04 as the base operating system. This ensures a consistent and reliable environment for users who want to deploy BunkerWeb using Vagrant. +!!! note "Supported Base Images" + Please be aware that the provided Vagrant boxes are based **exclusively on Ubuntu 22.04 "Jammy"**. While BunkerWeb supports other Linux distributions, the Vagrant setup currently only supports Ubuntu 22.04 as the base operating system. This ensures a consistent and reliable environment for users who want to deploy BunkerWeb using Vagrant. Similar to other BunkerWeb integrations, the Vagrant setup uses **NGINX version 1.24.0**. This specific version is required to ensure compatibility and smooth functioning with BunkerWeb. Additionally, the Vagrant box includes **PHP** pre-installed, providing a ready-to-use environment for hosting PHP-based applications alongside BunkerWeb. By using the provided Vagrant box based on Ubuntu 22.04 "Jammy", you benefit from a well-configured and integrated setup, allowing you to focus on developing and securing your applications with BunkerWeb without worrying about the underlying infrastructure. -Here are the steps to install BunkerWeb using Vagrant on Ubuntu with the supported virtualization providers (VirtualBox, VMware, and libvirt): +Here are the steps to install BunkerWeb using Vagrant on Ubuntu with the supported virtualization providers (VirtualBox, and libvirt): - -1. Make sure you have Vagrant and one of the supported virtualization providers (VirtualBox, VMware, or libvirt) installed on your system. +1. Make sure you have Vagrant and one of the supported virtualization providers (VirtualBox or libvirt) installed on your system. 2. There are two ways to install the Vagrant box with BunkerWeb: either by using a provided Vagrantfile to configure your virtual machine or by creating a new box based on the existing BunkerWeb Vagrant box, offering you flexibility in how you set up your development environment. === "Vagrantfile" @@ -1259,7 +1201,6 @@ Here are the steps to install BunkerWeb using Vagrant on Ubuntu with the support Depending on the virtualization provider you choose, you may need to install additional plugins: - * For **VMware**, install the `vagrant-vmware-desktop` plugin. For more information, see the [Vagrant documentation](https://www.vagrantup.com/docs/providers). * For **libvirt**, install the `vagrant-libvirt plugin`. For more information, see the [Vagrant documentation](https://www.vagrantup.com/docs/providers). * For **VirtualBox**, install the `vagrant-vbguest` plugin. For more information, see the [Vagrant documentation](https://www.vagrantup.com/docs/providers). @@ -1271,14 +1212,13 @@ Here are the steps to install BunkerWeb using Vagrant on Ubuntu with the support Depending on the virtualization provider you choose, you may need to install additional plugins: - * For **VMware**, install the `vagrant-vmware-desktop` plugin. For more information, see the [Vagrant documentation](https://www.vagrantup.com/docs/providers). * For **libvirt**, install the `vagrant-libvirt plugin`. For more information, see the [Vagrant documentation](https://www.vagrantup.com/docs/providers). * For **VirtualBox**, install the `vagrant-vbguest` plugin. For more information, see the [Vagrant documentation](https://www.vagrantup.com/docs/providers). After installing the necessary plugins for your chosen virtualization provider, run the following command to start the virtual machine and install BunkerWeb: ```shell -vagrant up --provider=virtualbox # or --provider=vmware_desktop or --provider=libvirt +vagrant up --provider=virtualbox # or --provider=libvirt ``` Finally, to access the virtual machine using SSH, execute the following command: @@ -1298,9 +1238,6 @@ Vagrant.configure("2") do |config| # Uncomment the desired virtualization provider # For VirtualBox (default) config.vm.provider "virtualbox" - # For VMware - # config.vm.provider "vmware_desktop" # Windows - # config.vm.provider "vmware_workstation" # Linux # For libvirt # config.vm.provider "libvirt" end diff --git a/docs/migrating.md b/docs/migrating.md index efccfaf64..c5f577c90 100644 --- a/docs/migrating.md +++ b/docs/migrating.md @@ -2,7 +2,7 @@ !!! warning "Read this if you were a 1.4.X user" - A lot of things changed since the 1.4.X releases. Container-based integrations stacks contain more services but, trust us, fundamental principles of BunkerWeb are still there. You will find ready to use boilerplates for various integrations in the [misc/integrations](https://github.com/bunkerity/bunkerweb/tree/v1.5.0/misc/integrations) folder of the repository. + A lot of things changed since the 1.4.X releases. Container-based integrations stacks contain more services but, trust us, fundamental principles of BunkerWeb are still there. You will find ready to use boilerplates for various integrations in the [misc/integrations](https://github.com/bunkerity/bunkerweb/tree/v1.5.1/misc/integrations) folder of the repository. ## Scheduler diff --git a/docs/plugins.md b/docs/plugins.md index 2cb10eeb9..4cd8477bf 100644 --- a/docs/plugins.md +++ b/docs/plugins.md @@ -8,11 +8,13 @@ Here is the list of "official" plugins that we maintain (see the [bunkerweb-plug | Name | Version | Description | Link | | :------------: | :-----: | :------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------: | -| **ClamAV** | 1.0 | Automatically scans uploaded files with the ClamAV antivirus engine and denies the request when a file is detected as malicious. | [bunkerweb-plugins/clamav](https://github.com/bunkerity/bunkerweb-plugins/tree/main/clamav) | -| **CrowdSec** | 1.0 | CrowdSec bouncer for BunkerWeb. | [bunkerweb-plugins/crowdsec](https://github.com/bunkerity/bunkerweb-plugins/tree/main/crowdsec) | -| **Discord** | 1.0 | Send security notifications to a Discord channel using a Webhook. | [bunkerweb-plugins/discord](https://github.com/bunkerity/bunkerweb-plugins/tree/main/discord) | -| **Slack** | 1.0 | Send security notifications to a Slack channel using a Webhook. | [bunkerweb-plugins/slack](https://github.com/bunkerity/bunkerweb-plugins/tree/main/slack) | -| **VirusTotal** | 1.0 | Automatically scans uploaded files with the VirusTotal API and denies the request when a file is detected as malicious. | [bunkerweb-plugins/virustotal](https://github.com/bunkerity/bunkerweb-plugins/tree/main/virustotal) | +| **ClamAV** | 1.1 | Automatically scans uploaded files with the ClamAV antivirus engine and denies the request when a file is detected as malicious. | [bunkerweb-plugins/clamav](https://github.com/bunkerity/bunkerweb-plugins/tree/main/clamav) | +| **Coraza** | 1.1 | Inspect requests using a the Coraza WAF (alternative of ModSecurity). | [bunkerweb-plugins/coraza](https://github.com/bunkerity/bunkerweb-plugins/tree/main/coraza) | +| **CrowdSec** | 1.1 | CrowdSec bouncer for BunkerWeb. | [bunkerweb-plugins/crowdsec](https://github.com/bunkerity/bunkerweb-plugins/tree/main/crowdsec) | +| **Discord** | 1.1 | Send security notifications to a Discord channel using a Webhook. | [bunkerweb-plugins/discord](https://github.com/bunkerity/bunkerweb-plugins/tree/main/discord) | +| **Slack** | 1.1 | Send security notifications to a Slack channel using a Webhook. | [bunkerweb-plugins/slack](https://github.com/bunkerity/bunkerweb-plugins/tree/main/slack) | +| **VirusTotal** | 1.1 | Automatically scans uploaded files with the VirusTotal API and denies the request when a file is detected as malicious. | [bunkerweb-plugins/virustotal](https://github.com/bunkerity/bunkerweb-plugins/tree/main/virustotal) | +| **WebHook** | 1.1 | Send security notifications to a custom HTTP endpoint using a Webhook. | [bunkerweb-plugins/webhook](https://github.com/bunkerity/bunkerweb-plugins/tree/main/webhook) | ## How to use a plugin @@ -20,7 +22,7 @@ Here is the list of "official" plugins that we maintain (see the [bunkerweb-plug If you want to quickly install external plugins, you can use the `EXTERNAL_PLUGIN_URLS` setting. It takes a list of URLs, separated with space, pointing to compressed (zip format) archive containing one or more plugin(s). -You can use the following value if you want to automatically install the official plugins : `EXTERNAL_PLUGIN_URLS=https://github.com/bunkerity/bunkerweb-plugins/archive/refs/tags/v1.0.zip` +You can use the following value if you want to automatically install the official plugins : `EXTERNAL_PLUGIN_URLS=https://github.com/bunkerity/bunkerweb-plugins/archive/refs/tags/v1.1.zip` ### Manual @@ -56,7 +58,7 @@ The first step is to install the plugin by putting the plugin files inside the c services: ... bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 volumes: - ./bw-data:/data ... @@ -93,7 +95,7 @@ The first step is to install the plugin by putting the plugin files inside the c services: ... bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 volumes: - ./bw-data:/data ... @@ -132,7 +134,7 @@ The first step is to install the plugin by putting the plugin files inside the c services: ... bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 volumes: - /shared/bw-plugins:/data/plugins ... @@ -179,7 +181,7 @@ The first step is to install the plugin by putting the plugin files inside the c serviceAccountName: sa-bunkerweb containers: - name: bunkerweb-scheduler - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 imagePullPolicy: Always env: - name: KUBERNETES_MODE @@ -260,7 +262,7 @@ The first step is to install the plugin by putting the plugin files inside the c !!! tip "Existing plugins" - If the documentation is not enough, you can have a look at the existing source code of [official plugins](https://github.com/bunkerity/bunkerweb-plugins) and the [core plugins](https://github.com/bunkerity/bunkerweb/tree/v1.5.0/src/common/core) (already included in BunkerWeb but they are plugins, technically speaking). + If the documentation is not enough, you can have a look at the existing source code of [official plugins](https://github.com/bunkerity/bunkerweb-plugins) and the [core plugins](https://github.com/bunkerity/bunkerweb/tree/v1.5.1/src/common/core) (already included in BunkerWeb but they are plugins, technically speaking). The first step is to create a folder that will contain the plugin : @@ -275,30 +277,29 @@ A file named **plugin.json** and written at the root of the plugin folder must c ```json { - "id": "myplugin", - "order": 42, - "name": "My Plugin", - "description": "Just an example plugin.", - "version": "1.0", + "id": "myplugin", + "name": "My Plugin", + "description": "Just an example plugin.", + "version": "1.0", "stream": "partial", - "settings": { - "DUMMY_SETTING": { - "context": "multisite", - "default": "1234", - "help": "Here is the help of the setting.", - "id": "dummy-id", - "label": "Dummy setting", - "regex": "^.*$", - "type": "text" - } - }, - "jobs": [ - { - "name": "my-job", - "file": "my-job.py", - "every": "hour" - } - ] + "settings": { + "DUMMY_SETTING": { + "context": "multisite", + "default": "1234", + "help": "Here is the help of the setting.", + "id": "dummy-id", + "label": "Dummy setting", + "regex": "^.*$", + "type": "text" + } + }, + "jobs": [ + { + "name": "my-job", + "file": "my-job.py", + "every": "hour" + } + ] } ``` @@ -307,7 +308,6 @@ Here are the details of the fields : | Field | Mandatory | Type | Description | | :-----------: | :-------: | :----: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | yes | string | Internal ID for the plugin : must be unique among other plugins (including "core" ones) and contain only lowercase chars. | -| `order` | yes | int | When the plugin should be executed during the access phase : `1` for whitelisting, `2` for blacklisting, `3` for "standard security feature" or `999` if your settings don't use the access phase. | | `name` | yes | string | Name of your plugin. | | `description` | yes | string | Description of your plugin. | | `version` | yes | string | Version of your plugin. | @@ -507,7 +507,7 @@ end !!! tip "More examples" - If you want to see the full list of available functions, you can have a look at the files present in the [lua directory](https://github.com/bunkerity/bunkerweb/tree/v1.5.0/src/bw/lua/bunkerweb) of the repository. + If you want to see the full list of available functions, you can have a look at the files present in the [lua directory](https://github.com/bunkerity/bunkerweb/tree/v1.5.1/src/bw/lua/bunkerweb) of the repository. ### Jobs diff --git a/docs/quickstart-guide.md b/docs/quickstart-guide.md index 4daf13da5..fb721ade2 100644 --- a/docs/quickstart-guide.md +++ b/docs/quickstart-guide.md @@ -4,7 +4,7 @@ We assume that you're already familiar with the [core concepts](concepts.md) and you have followed the [integrations instructions](integrations.md) for your environment. !!! tip "Going further" - To demonstrate the use of BunkerWeb, we will deploy a dummy "Hello World" web application as an example. See the [examples folder](https://github.com/bunkerity/bunkerweb/tree/v1.5.0/examples) of the repository to get real-world examples. + To demonstrate the use of BunkerWeb, we will deploy a dummy "Hello World" web application as an example. See the [examples folder](https://github.com/bunkerity/bunkerweb/tree/v1.5.1/examples) of the repository to get real-world examples. ## Protect HTTP applications @@ -35,7 +35,7 @@ You will find more settings about reverse proxy in the [settings section](settin - bw-services bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -52,7 +52,7 @@ You will find more settings about reverse proxy in the [settings section](settin - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - bunkerweb - bw-docker @@ -65,11 +65,12 @@ You will find more settings about reverse proxy in the [settings section](settin - bw-docker bw-docker: - image: tecnativa/docker-socket-proxy + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker @@ -385,7 +386,7 @@ You will find more settings about reverse proxy in the [settings section](settin - bw-services bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -405,7 +406,7 @@ You will find more settings about reverse proxy in the [settings section](settin - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - bunkerweb - bw-docker @@ -418,11 +419,12 @@ You will find more settings about reverse proxy in the [settings section](settin - bw-docker bw-docker: - image: tecnativa/docker-socket-proxy + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker @@ -820,7 +822,7 @@ REAL_IP_HEADER=X-Forwarded-For ```yaml mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ... environment: - USE_REAL_IP=yes @@ -835,7 +837,7 @@ REAL_IP_HEADER=X-Forwarded-For ```yaml mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ... environment: - USE_REAL_IP=yes @@ -850,7 +852,7 @@ REAL_IP_HEADER=X-Forwarded-For ```yaml mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ... environment: - USE_REAL_IP=yes @@ -970,7 +972,7 @@ REAL_IP_HEADER=proxy_protocol ```yaml mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ... environment: - USE_REAL_IP=yes @@ -986,7 +988,7 @@ REAL_IP_HEADER=proxy_protocol ```yaml mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ... environment: - USE_REAL_IP=yes @@ -1002,7 +1004,7 @@ REAL_IP_HEADER=proxy_protocol ```yaml mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ... environment: - USE_REAL_IP=yes @@ -1111,11 +1113,11 @@ REAL_IP_HEADER=proxy_protocol !!! warning "Feature is in beta" This feature is not production-ready. Feel free to test it and report us any bug using [issues](https://github.com/bunkerity/bunkerweb/issues) in the GitHub repository. -BunkerWeb can also act as **generic UDP/TCP reverse proxy** : you can protect any network-based applications working at least on layer 4 of the OSI model. Behind the hood, it leverages the [stream module](https://nginx.org/en/docs/stream/ngx_stream_core_module.html) of NGINX instead of using the "classical" http one. +BunkerWeb offers the capability to function as a **generic UDP/TCP reverse proxy**, allowing you to protect any network-based applications operating at least on layer 4 of the OSI model. Instead of utilizing the "classical" HTTP module, BunkerWeb leverages the [stream module](https://nginx.org/en/docs/stream/ngx_stream_core_module.html) of NGINX. -Please note that not all settings and security features are available when using the stream module. You will find more info about that in the [security tuning](security-tuning.md) and [settings](settings.md) sections of the documentation. +It's important to note that not all settings and security features are available when using the stream module. Additional information on this can be found in the [security tuning](security-tuning.md) and [settings](settings.md) sections of the documentation. -Configuration for a basic reverse proxy is very similar to the HTTP one because it uses the same `USE_REVERSE_PROXY=yes` and `REVERSE_PROXY_HOST=myapp:4242` settings. Even the settings used when BunkerWeb is [behind a Load Balancer](#behind-load-balancer-or-reverse-proxy) are the same (but for obvious reasons, only **PROXY protocol** is supported). +Configuring a basic reverse proxy is quite similar to the HTTP setup, as it involves using the same settings: `USE_REVERSE_PROXY=yes` and `REVERSE_PROXY_HOST=myapp:4242`. Even when BunkerWeb is positioned behind a Load Balancer, the settings remain the same (with **PROXY protocol** being the supported option due to evident reasons). On top of that, the following specific settings are used : @@ -1148,7 +1150,7 @@ For complete list of settings regarding `stream` mode, please refer to the [sett - bw-services bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 # Keep it if you want to use Let's Encrypt automation - 10000:10000 # app1 @@ -1170,7 +1172,7 @@ For complete list of settings regarding `stream` mode, please refer to the [sett - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - bunkerweb - bw-docker @@ -1183,11 +1185,12 @@ For complete list of settings regarding `stream` mode, please refer to the [sett - bw-docker bw-docker: - image: tecnativa/docker-socket-proxy + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker @@ -1218,7 +1221,7 @@ For complete list of settings regarding `stream` mode, please refer to the [sett services: bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 # Keep it if you want to use Let's Encrypt automation - 10000:10000 # app1 @@ -1276,7 +1279,7 @@ For complete list of settings regarding `stream` mode, please refer to the [sett services: bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: # Keep it if you want to use Let's Encrypt automation - published: 80 @@ -1426,21 +1429,23 @@ For complete list of settings regarding `stream` mode, please refer to the [sett ## Custom configurations -Because BunkerWeb is based on the NGINX web server, you can add custom NGINX configurations in different NGINX contexts. You can also apply custom configurations for the ModSecurity WAF which is a core component of BunkerWeb (more info [here](security-tuning.md#modsecurity)). Here is the list of custom configurations types : +To customize and add custom configurations to BunkerWeb, you can take advantage of its NGINX foundation. Custom NGINX configurations can be added in different NGINX contexts, including configurations for the ModSecurity Web Application Firewall (WAF), which is a core component of BunkerWeb. More details about ModSecurity configurations can be found [here](security-tuning.md#modsecurity). -- **http** : http level of NGINX -- **server-http** : http/server level of NGINX -- **default-server-http** : server level of NGINX (only apply to the "default server" when the name supplied by the client doesn't match any server name in `SERVER_NAME`) -- **modsec-crs** : before the OWASP Core Rule Set is loaded -- **modsec** : after the OWASP Core Rule Set is loaded (also used if CRS is not loaded) -- **stream** : stream level of NGINX -- **server-stream** : stream/server level of NGINX +Here are the available types of custom configurations: -Custom configurations can be applied globally or only for a specific server when applicable and if the multisite mode is enabled. +- **http**: Configurations at the HTTP level of NGINX. +- **server-http**: Configurations at the HTTP/Server level of NGINX. +- **default-server-http**: Configurations at the Server level of NGINX, specifically for the "default server" when the supplied client name doesn't match any server name in `SERVER_NAME`. +- **modsec-crs**: Configurations applied before the OWASP Core Rule Set is loaded. +- **modsec**: Configurations applied after the OWASP Core Rule Set is loaded, or used when the Core Rule Set is not loaded. +- **stream**: Configurations at the Stream level of NGINX. +- **server-stream**: Configurations at the Stream/Server level of NGINX. -The howto depends on the integration used but under the hood, applying custom configurations is done by adding files ending with the .conf suffix in their name to specific folders. To apply a custom configuration for a specific server, the file is written to a subfolder which is named as the primary server name. +Custom configurations can be applied globally or specifically for a particular server, depending on the applicable context and whether the [multisite mode](concepts.md#multisite-mode) is enabled. -Some integrations offer a more convenient way of applying configurations such as using [Configs](https://docs.docker.com/engine/swarm/configs/) with Swarm or [ConfigMap](https://kubernetes.io/docs/concepts/configuration/configmap/) with Kubernetes. +The method for applying custom configurations depends on the integration being used. However, the underlying process involves adding files with the `.conf` suffix to specific folders. To apply a custom configuration for a specific server, the file should be placed in a subfolder named after the primary server name. + +Some integrations provide more convenient ways to apply configurations, such as using [Configs](https://docs.docker.com/engine/swarm/configs/) in Docker Swarm or [ConfigMap](https://kubernetes.io/docs/concepts/configuration/configmap/) in Kubernetes. These options offer simpler approaches for managing and applying configurations. === "Docker" @@ -1462,7 +1467,7 @@ Some integrations offer a more convenient way of applying configurations such as ```yaml ... mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 environment: - | CUSTOM_CONF_SERVER_HTTP_hello-world= @@ -1505,7 +1510,7 @@ Some integrations offer a more convenient way of applying configurations such as ```yaml mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 volumes: - ./bw-data:/data ... @@ -1574,7 +1579,7 @@ Some integrations offer a more convenient way of applying configurations such as ```yaml myautoconf: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 volumes: - ./bw-data:/data ... @@ -1807,7 +1812,7 @@ BunkerWeb supports PHP using external or remote [PHP-FPM](https://www.php.net/ma - bw-services bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 volumes: - ./www:/var/www/html ports: @@ -1830,7 +1835,7 @@ BunkerWeb supports PHP using external or remote [PHP-FPM](https://www.php.net/ma - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - bunkerweb - bw-docker @@ -1843,11 +1848,12 @@ BunkerWeb supports PHP using external or remote [PHP-FPM](https://www.php.net/ma - bw-docker bw-docker: - image: tecnativa/docker-socket-proxy + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker @@ -1907,7 +1913,7 @@ BunkerWeb supports PHP using external or remote [PHP-FPM](https://www.php.net/ma services: bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 volumes: - ./www:/var/www/html labels: @@ -1921,7 +1927,7 @@ BunkerWeb supports PHP using external or remote [PHP-FPM](https://www.php.net/ma - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - bunkerweb - bw-docker @@ -1933,11 +1939,12 @@ BunkerWeb supports PHP using external or remote [PHP-FPM](https://www.php.net/ma - bw-docker bw-docker: - image: tecnativa/docker-socket-proxy + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker @@ -2064,7 +2071,7 @@ BunkerWeb supports PHP using external or remote [PHP-FPM](https://www.php.net/ma services: bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 volumes: - /shared/www:/var/www/html ... @@ -2343,7 +2350,7 @@ By default, BunkerWeb will only listen on IPv4 adresses and won't use IPv6 for n services: bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 environment: - USE_IPv6=yes @@ -2388,7 +2395,7 @@ By default, BunkerWeb will only listen on IPv4 adresses and won't use IPv6 for n services: bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 environment: - USE_IPv6=yes diff --git a/docs/requirements.txt b/docs/requirements.txt index c56364e5c..d9fb74db5 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,6 +1,6 @@ -mkdocs==1.4.3 -mkdocs-material==9.1.13 -pytablewriter==0.64.2 +mkdocs==1.5.2 +mkdocs-material==9.1.21 +pytablewriter==1.0.0 mike==1.1.2 jinja2<3.1.0 -mkdocs-print-site-plugin==2.3.4 \ No newline at end of file +mkdocs-print-site-plugin==2.3.5 \ No newline at end of file diff --git a/docs/robots.txt b/docs/robots.txt new file mode 100644 index 000000000..076a7bc16 --- /dev/null +++ b/docs/robots.txt @@ -0,0 +1,4 @@ +User-agent: * +Allow: /latest/ + +Sitemap: https://docs.bunkerweb.io/sitemap.xml \ No newline at end of file diff --git a/docs/security-tuning.md b/docs/security-tuning.md index ad3c14d31..e008284aa 100644 --- a/docs/security-tuning.md +++ b/docs/security-tuning.md @@ -63,6 +63,12 @@ STREAM support :x: You can automatically remove verbose headers in the HTTP responses by using the `REMOVE_HEADERS` setting (default : `Server X-Powered-By X-AspNet-Version X-AspNetMvc-Version`). +#### Keep upstream headers + +STREAM support :x: + +You can automatically keep headers from upstream servers and prevent BunkerWeb from overriding them in the HTTP responses by using the `KEEP_UPSTREAM_HEADERS` setting (default : `Content-Security-Policy Permissions-Policy Feature-Policy X-Frame-Options`). A special value `*` is available to keep all headers. List of headers to keep must be separated with a space. Note that if the header is not present in the upstream response, it will be added by BunkerWeb. + #### Cookies STREAM support :x: @@ -127,12 +133,10 @@ Besides the HTTPS configuration, the following settings related to HTTPS can be | :---------------------------: | :---------------: | :----------------------------------------------------------------------------------------------------------- | | `REDIRECT_HTTP_TO_HTTPS` | `no` | When set to `yes`, will redirect every HTTP request to HTTPS even if BunkerWeb is not configured with HTTPS. | | `AUTO_REDIRECT_HTTP_TO_HTTPS` | `yes` | When set to `yes`, will redirect every HTTP request to HTTPS only if BunkerWeb is configured with HTTPS. | -| `HTTPS_PROTOCOLS` | `TLSv1.2 TLSv1.3` | List of supported SSL/TLS protocols when HTTPS is enabled. | +| `SSL_PROTOCOLS` | `TLSv1.2 TLSv1.3` | List of supported SSL/TLS protocols when SSL is enabled. | | `HTTP2` | `yes` | When set to `yes`, will enable HTTP2 protocol support when using HTTPS. | | `LISTEN_HTTP` | `yes` | When set to `no`, BunkerWeb will not listen for HTTP requests. Useful if you want HTTPS only for example. | -When using stream, the `SSL_PROTOCOLS` can be used which takes the same value as the `HTTPS_PROTOCOLS` one. - ### Let's Encrypt STREAM support :white_check_mark: @@ -155,13 +159,14 @@ STREAM support :white_check_mark: If you want to use your own certificates, here is the list of related settings : -| Setting | Default | Description | -| :-----------------: | :-----: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `USE_CUSTOM_SSL` | `no` | When set to `yes`, HTTPS will be enabled with custom certificates. | -| `CUSTOM_SSL_CERT` | | Full path to the certificate. If you have one or more intermediate certificate(s) in your chain of trust, you will need to provide the bundle (more info [here](https://nginx.org/en/docs/http/configuring_https_servers.html#chains)). | -| `CUSTOM_SSL_KEY` | | Full path to the private key. | +| Setting |Default| Context |Multiple| Description | +|-----------------|-------|---------|--------|--------------------------------------------------------------------------------| +|`USE_CUSTOM_SSL` |`no` |multisite|no |Use custom HTTPS certificate. | +|`CUSTOM_SSL_CERT`| |multisite|no |Full path of the certificate or bundle file (must be readable by the scheduler).| +|`CUSTOM_SSL_KEY` | |multisite|no |Full path of the key file (must be readable by the scheduler). | -When `USE_CUSTOM_HTTPS` is set to `yes`, BunkerWeb will check every day if the custom certificate specified in `CUSTOM_HTTPS_CERT` is modified and will reload NGINX if that's the case. + +When `USE_CUSTOM_SSL` is set to `yes`, BunkerWeb will check every day if the custom certificate specified in `CUSTOM_SSL_CERT` is modified and will reload NGINX if that's the case. When using stream mode, you will need to use the `LISTEN_STREAM_PORT_SSL` setting in order to choose your listening SSL/TLS port. @@ -250,6 +255,7 @@ That kind of security is implemented but not enabled by default in BunkerWeb and - **Captcha** : force the client to solve a classical captcha (no external dependencies) - **hCaptcha** : force the client to solve a captcha from hCaptcha - **reCAPTCHA** : force the client to get a minimum score with Google reCAPTCHA +- **Turnstile** : enforce rate limiting and access control for APIs and web applications using various mechanisms with Coudflare Turnstile Here is the list of related settings : @@ -262,6 +268,8 @@ Here is the list of related settings : |`ANTIBOT_RECAPTCHA_SECRET` | |multisite|no |Secret for reCAPTCHA challenge. | |`ANTIBOT_HCAPTCHA_SITEKEY` | |multisite|no |Sitekey for hCaptcha challenge. | |`ANTIBOT_HCAPTCHA_SECRET` | |multisite|no |Secret for hCaptcha challenge. | +|`ANTIBOT_TURNSTILE_SITEKEY`| |multisite|no |Sitekey for Turnstile challenge. | +|`ANTIBOT_TURNSTILE_SECRET` | |multisite|no |Secret for Turnstile challenge. | |`ANTIBOT_TIME_RESOLVE` |`60` |multisite|no |Maximum time (in seconds) clients have to resolve the challenge. Once this time has passed, a new challenge will be generated.| |`ANTIBOT_TIME_VALID` |`86400` |multisite|no |Maximum validity time of solved challenges. Once this time has passed, clients will need to resolve a new one. | @@ -476,7 +484,7 @@ You can quickly protect sensitive resources like the admin area for example, by ### Auth request -You can deploy complex authentication (e.g. SSO), by using the auth request settings (see [here](https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-subrequest-authentication/) for more information on the feature). Please note that you will find [Authelia](https://www.authelia.com/) and [Authentik](https://goauthentik.io/) examples in the [repository](https://github.com/bunkerity/bunkerweb/tree/v1.5.0/examples). +You can deploy complex authentication (e.g. SSO), by using the auth request settings (see [here](https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-subrequest-authentication/) for more information on the feature). Please note that you will find [Authelia](https://www.authelia.com/) and [Authentik](https://goauthentik.io/) examples in the [repository](https://github.com/bunkerity/bunkerweb/tree/v1.5.1/examples). **Auth request settings are related to reverse proxy rules.** diff --git a/docs/settings.md b/docs/settings.md index fecd02f9f..051a63d81 100644 --- a/docs/settings.md +++ b/docs/settings.md @@ -67,6 +67,8 @@ Bot detection by using a challenge. |`ANTIBOT_RECAPTCHA_SECRET` | |multisite|no |Secret for reCAPTCHA challenge. | |`ANTIBOT_HCAPTCHA_SITEKEY` | |multisite|no |Sitekey for hCaptcha challenge. | |`ANTIBOT_HCAPTCHA_SECRET` | |multisite|no |Secret for hCaptcha challenge. | +|`ANTIBOT_TURNSTILE_SITEKEY`| |multisite|no |Sitekey for Turnstile challenge. | +|`ANTIBOT_TURNSTILE_SECRET` | |multisite|no |Secret for Turnstile challenge. | |`ANTIBOT_TIME_RESOLVE` |`60` |multisite|no |Maximum time (in seconds) clients have to resolve the challenge. Once this time has passed, a new challenge will be generated.| |`ANTIBOT_TIME_VALID` |`86400` |multisite|no |Maximum validity time of solved challenges. Once this time has passed, clients will need to resolve a new one. | @@ -159,16 +161,19 @@ STREAM support :x: Cross-Origin Resource Sharing. -| Setting | Default | Context |Multiple| Description | -|------------------------|------------------------------------------------------------------------------------|---------|--------|-------------------------------------------------------------------| -|`USE_CORS` |`no` |multisite|no |Use CORS | -|`CORS_ALLOW_ORIGIN` |`*` |multisite|no |Allowed origins to make CORS requests : PCRE regex or *. | -|`CORS_EXPOSE_HEADERS` |`Content-Length,Content-Range` |multisite|no |Value of the Access-Control-Expose-Headers header. | -|`CORS_MAX_AGE` |`86400` |multisite|no |Value of the Access-Control-Max-Age header. | -|`CORS_ALLOW_CREDENTIALS`|`no` |multisite|no |Send the Access-Control-Allow-Credentials header. | -|`CORS_ALLOW_METHODS` |`GET, POST, OPTIONS` |multisite|no |Value of the Access-Control-Allow-Methods header. | -|`CORS_ALLOW_HEADERS` |`DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range`|multisite|no |Value of the Access-Control-Allow-Headers header. | -|`CORS_DENY_REQUEST` |`yes` |multisite|no |Deny request and don't send it to backend if Origin is not allowed.| +| Setting | Default | Context |Multiple| Description | +|------------------------------|------------------------------------------------------------------------------------|---------|--------|-------------------------------------------------------------------| +|`USE_CORS` |`no` |multisite|no |Use CORS | +|`CORS_ALLOW_ORIGIN` |`*` |multisite|no |Allowed origins to make CORS requests : PCRE regex or *. | +|`CORS_EXPOSE_HEADERS` |`Content-Length,Content-Range` |multisite|no |Value of the Access-Control-Expose-Headers header. | +|`CROSS_ORIGIN_OPENER_POLICY` | |multisite|no |Value for the Cross-Origin-Opener-Policy header. | +|`CROSS_ORIGIN_EMBEDDER_POLICY`| |multisite|no |Value for the Cross-Origin-Embedder-Policy header. | +|`CROSS_ORIGIN_RESOURCE_POLICY`| |multisite|no |Value for the Cross-Origin-Resource-Policy header. | +|`CORS_MAX_AGE` |`86400` |multisite|no |Value of the Access-Control-Max-Age header. | +|`CORS_ALLOW_CREDENTIALS` |`no` |multisite|no |Send the Access-Control-Allow-Credentials header. | +|`CORS_ALLOW_METHODS` |`GET, POST, OPTIONS` |multisite|no |Value of the Access-Control-Allow-Methods header. | +|`CORS_ALLOW_HEADERS` |`DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range`|multisite|no |Value of the Access-Control-Allow-Headers header. | +|`CORS_DENY_REQUEST` |`yes` |multisite|no |Deny request and don't send it to backend if Origin is not allowed.| ### Client cache @@ -200,11 +205,11 @@ STREAM support :white_check_mark: Choose custom certificate for HTTPS. -| Setting |Default| Context |Multiple| Description | -|-----------------|-------|---------|--------|--------------------------------------------| -|`USE_CUSTOM_SSL` |`no` |multisite|no |Use custom HTTPS certificate. | -|`CUSTOM_SSL_CERT`| |multisite|no |Full path of the certificate or bundle file.| -|`CUSTOM_SSL_KEY` | |multisite|no |Full path of the key file. | +| Setting |Default| Context |Multiple| Description | +|-----------------|-------|---------|--------|--------------------------------------------------------------------------------| +|`USE_CUSTOM_SSL` |`no` |multisite|no |Use custom HTTPS certificate. | +|`CUSTOM_SSL_CERT`| |multisite|no |Full path of the certificate or bundle file (must be readable by the scheduler).| +|`CUSTOM_SSL_KEY` | |multisite|no |Full path of the key file (must be readable by the scheduler). | ### DB @@ -288,20 +293,22 @@ STREAM support :x: Manage HTTP headers sent to clients. -| Setting | Default | Context |Multiple| Description | -|---------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|--------|----------------------------------------------------------------------------------------------| -|`CUSTOM_HEADER` | |multisite|yes |Custom header to add (HeaderName: HeaderValue). | -|`REMOVE_HEADERS` |`Server X-Powered-By X-AspNet-Version X-AspNetMvc-Version` |multisite|no |Headers to remove (Header1 Header2 Header3 ...) | -|`STRICT_TRANSPORT_SECURITY`|`max-age=31536000` |multisite|no |Value for the Strict-Transport-Security header. | -|`COOKIE_FLAGS` |`* HttpOnly SameSite=Lax` |multisite|yes |Cookie flags automatically added to all cookies (value accepted for nginx_cookie_flag_module).| -|`COOKIE_AUTO_SECURE_FLAG` |`yes` |multisite|no |Automatically add the Secure flag to all cookies. | -|`CONTENT_SECURITY_POLICY` |`object-src 'none'; form-action 'self'; frame-ancestors 'self';` |multisite|no |Value for the Content-Security-Policy header. | -|`REFERRER_POLICY` |`strict-origin-when-cross-origin` |multisite|no |Value for the Referrer-Policy header. | -|`PERMISSIONS_POLICY` |`accelerometer=(), ambient-light-sensor=(), autoplay=(), battery=(), camera=(), cross-origin-isolated=(), display-capture=(), document-domain=(), encrypted-media=(), execution-while-not-rendered=(), execution-while-out-of-viewport=(), fullscreen=(), geolocation=(), gyroscope=(), hid=(), idle-detection=(), magnetometer=(), microphone=(), midi=(), navigation-override=(), payment=(), picture-in-picture=(), publickey-credentials-get=(), screen-wake-lock=(), serial=(), usb=(), web-share=(), xr-spatial-tracking=()` |multisite|no |Value for the Permissions-Policy header. | -|`FEATURE_POLICY` |`accelerometer 'none'; ambient-light-sensor 'none'; autoplay 'none'; battery 'none'; camera 'none'; display-capture 'none'; document-domain 'none'; encrypted-media 'none'; execution-while-not-rendered 'none'; execution-while-out-of-viewport 'none'; fullscreen 'none'; geolocation 'none'; gyroscope 'none'; layout-animation 'none'; legacy-image-formats 'none'; magnetometer 'none'; microphone 'none'; midi 'none'; navigation-override 'none'; payment 'none'; picture-in-picture 'none'; publickey-credentials-get 'none'; speaker-selection 'none'; sync-xhr 'none'; unoptimized-images 'none'; unsized-media 'none'; usb 'none'; screen-wake-lock 'none'; web-share 'none'; xr-spatial-tracking 'none';`|multisite|no |Value for the Feature-Policy header. | -|`X_FRAME_OPTIONS` |`SAMEORIGIN` |multisite|no |Value for the X-Frame-Options header. | -|`X_CONTENT_TYPE_OPTIONS` |`nosniff` |multisite|no |Value for the X-Content-Type-Options header. | -|`X_XSS_PROTECTION` |`1; mode=block` |multisite|no |Value for the X-XSS-Protection header. | +| Setting | Default | Context |Multiple| Description | +|-------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|--------|----------------------------------------------------------------------------------------------| +|`CUSTOM_HEADER` | |multisite|yes |Custom header to add (HeaderName: HeaderValue). | +|`REMOVE_HEADERS` |`Server Expect-CT X-Powered-By X-AspNet-Version X-AspNetMvc-Version` |multisite|no |Headers to remove (Header1 Header2 Header3 ...) | +|`KEEP_UPSTREAM_HEADERS` |`Content-Security-Policy Permissions-Policy Feature-Policy X-Frame-Options` |multisite|no |Headers to keep from upstream (Header1 Header2 Header3 ... or * for all). | +|`STRICT_TRANSPORT_SECURITY` |`max-age=31536000` |multisite|no |Value for the Strict-Transport-Security header. | +|`COOKIE_FLAGS` |`* HttpOnly SameSite=Lax` |multisite|yes |Cookie flags automatically added to all cookies (value accepted for nginx_cookie_flag_module).| +|`COOKIE_AUTO_SECURE_FLAG` |`yes` |multisite|no |Automatically add the Secure flag to all cookies. | +|`CONTENT_SECURITY_POLICY` |`object-src 'none'; form-action 'self'; frame-ancestors 'self';` |multisite|no |Value for the Content-Security-Policy header. | +|`CONTENT_SECURITY_POLICY_REPORT_ONLY`|`no` |multisite|no |Send reports for violations of the Content-Security-Policy header instead of blocking them. | +|`REFERRER_POLICY` |`strict-origin-when-cross-origin` |multisite|no |Value for the Referrer-Policy header. | +|`PERMISSIONS_POLICY` |`accelerometer=(), ambient-light-sensor=(), autoplay=(), battery=(), camera=(), cross-origin-isolated=(), display-capture=(), document-domain=(), encrypted-media=(), execution-while-not-rendered=(), execution-while-out-of-viewport=(), fullscreen=(), geolocation=(), gyroscope=(), hid=(), idle-detection=(), magnetometer=(), microphone=(), midi=(), navigation-override=(), payment=(), picture-in-picture=(), publickey-credentials-get=(), screen-wake-lock=(), serial=(), usb=(), web-share=(), xr-spatial-tracking=()` |multisite|no |Value for the Permissions-Policy header. | +|`FEATURE_POLICY` |`accelerometer 'none'; ambient-light-sensor 'none'; autoplay 'none'; battery 'none'; camera 'none'; display-capture 'none'; document-domain 'none'; encrypted-media 'none'; execution-while-not-rendered 'none'; execution-while-out-of-viewport 'none'; fullscreen 'none'; geolocation 'none'; gyroscope 'none'; layout-animation 'none'; legacy-image-formats 'none'; magnetometer 'none'; microphone 'none'; midi 'none'; navigation-override 'none'; payment 'none'; picture-in-picture 'none'; publickey-credentials-get 'none'; speaker-selection 'none'; sync-xhr 'none'; unoptimized-images 'none'; unsized-media 'none'; usb 'none'; screen-wake-lock 'none'; web-share 'none'; xr-spatial-tracking 'none';`|multisite|no |Value for the Feature-Policy header. | +|`X_FRAME_OPTIONS` |`SAMEORIGIN` |multisite|no |Value for the X-Frame-Options header. | +|`X_CONTENT_TYPE_OPTIONS` |`nosniff` |multisite|no |Value for the X-Content-Type-Options header. | +|`X_XSS_PROTECTION` |`1; mode=block` |multisite|no |Value for the X-XSS-Protection header. | ### Let's Encrypt @@ -337,25 +344,25 @@ STREAM support :warning: Miscellaneous settings. -| Setting | Default | Context |Multiple| Description | -|-----------------------------|-----------------------|---------|--------|----------------------------------------------------------------------------------------------------------------------| -|`DISABLE_DEFAULT_SERVER` |`no` |global |no |Close connection if the request vhost is unknown. | -|`REDIRECT_HTTP_TO_HTTPS` |`no` |multisite|no |Redirect all HTTP request to HTTPS. | -|`AUTO_REDIRECT_HTTP_TO_HTTPS`|`yes` |multisite|no |Try to detect if HTTPS is used and activate HTTP to HTTPS redirection if that's the case. | -|`ALLOWED_METHODS` |`GET|POST|HEAD` |multisite|no |Allowed HTTP and WebDAV methods, separated with pipes to be sent by clients. | -|`MAX_CLIENT_SIZE` |`10m` |multisite|no |Maximum body size (0 for infinite). | -|`SERVE_FILES` |`yes` |multisite|no |Serve files from the local folder. | -|`ROOT_FOLDER` | |multisite|no |Root folder containing files to serve (/var/www/html/{server_name} if unset). | -|`SSL_PROTOCOLS` |`TLSv1.2 TLSv1.3` |multisite|no |The supported version of TLS. We recommend the default value TLSv1.2 TLSv1.3 for compatibility reasons. | -|`HTTP2` |`yes` |multisite|no |Support HTTP2 protocol when HTTPS is enabled. | -|`LISTEN_HTTP` |`yes` |multisite|no |Respond to (insecure) HTTP requests. | -|`USE_OPEN_FILE_CACHE` |`no` |multisite|no |Enable open file cache feature | -|`OPEN_FILE_CACHE` |`max=1000 inactive=20s`|multisite|no |Open file cache directive | -|`OPEN_FILE_CACHE_ERRORS` |`yes` |multisite|no |Enable open file cache for errors | -|`OPEN_FILE_CACHE_MIN_USES` |`2` |multisite|no |Enable open file cache minimum uses | -|`OPEN_FILE_CACHE_VALID` |`30s` |multisite|no |Open file cache valid time | -|`EXTERNAL_PLUGIN_URLS` | |global |no |List of external plugins URLs (direct download to .zip file) to download and install (URLs are separated with space). | -|`DENY_HTTP_STATUS` |`403` |global |no |HTTP status code to send when the request is denied (403 or 444). When using 444, BunkerWeb will close the connection.| +| Setting | Default | Context |Multiple| Description | +|-----------------------------|-----------------------|---------|--------|-----------------------------------------------------------------------------------------------------------------------------| +|`DISABLE_DEFAULT_SERVER` |`no` |global |no |Close connection if the request vhost is unknown. | +|`REDIRECT_HTTP_TO_HTTPS` |`no` |multisite|no |Redirect all HTTP request to HTTPS. | +|`AUTO_REDIRECT_HTTP_TO_HTTPS`|`yes` |multisite|no |Try to detect if HTTPS is used and activate HTTP to HTTPS redirection if that's the case. | +|`ALLOWED_METHODS` |`GET|POST|HEAD` |multisite|no |Allowed HTTP and WebDAV methods, separated with pipes to be sent by clients. | +|`MAX_CLIENT_SIZE` |`10m` |multisite|no |Maximum body size (0 for infinite). | +|`SERVE_FILES` |`yes` |multisite|no |Serve files from the local folder. | +|`ROOT_FOLDER` | |multisite|no |Root folder containing files to serve (/var/www/html/{server_name} if unset). | +|`SSL_PROTOCOLS` |`TLSv1.2 TLSv1.3` |multisite|no |The supported version of TLS. We recommend the default value TLSv1.2 TLSv1.3 for compatibility reasons. | +|`HTTP2` |`yes` |multisite|no |Support HTTP2 protocol when HTTPS is enabled. | +|`LISTEN_HTTP` |`yes` |multisite|no |Respond to (insecure) HTTP requests. | +|`USE_OPEN_FILE_CACHE` |`no` |multisite|no |Enable open file cache feature | +|`OPEN_FILE_CACHE` |`max=1000 inactive=20s`|multisite|no |Open file cache directive | +|`OPEN_FILE_CACHE_ERRORS` |`yes` |multisite|no |Enable open file cache for errors | +|`OPEN_FILE_CACHE_MIN_USES` |`2` |multisite|no |Enable open file cache minimum uses | +|`OPEN_FILE_CACHE_VALID` |`30s` |multisite|no |Open file cache valid time | +|`EXTERNAL_PLUGIN_URLS` | |global |no |List of external plugins URLs (direct download to .zip or .tar file) to download and install (URLs are separated with space).| +|`DENY_HTTP_STATUS` |`403` |global |no |HTTP status code to send when the request is denied (403 or 444). When using 444, BunkerWeb will close the connection. | ### ModSecurity @@ -409,6 +416,7 @@ Manage HTTP redirects. |-------------------------|-------|---------|--------|-------------------------------------------------| |`REDIRECT_TO` | |multisite|no |Redirect a whole site to another one. | |`REDIRECT_TO_REQUEST_URI`|`no` |multisite|no |Append the requested URI to the redirect address.| +|`REDIRECT_TO_STATUS_CODE`|`301` |multisite|no |Status code to send to client when redirecting. | ### Redis @@ -517,18 +525,18 @@ STREAM support :warning: Allow access based on internal and external IP/network/rDNS/ASN whitelists. -| Setting | Default | Context |Multiple| Description | -|---------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|--------|----------------------------------------------------------------------------------| -|`USE_WHITELIST` |`yes` |multisite|no |Activate whitelist feature. | -|`WHITELIST_IP` |`20.191.45.212 40.88.21.235 40.76.173.151 40.76.163.7 20.185.79.47 52.142.26.175 20.185.79.15 52.142.24.149 40.76.162.208 40.76.163.23 40.76.162.191 40.76.162.247 54.208.102.37 107.21.1.8`|multisite|no |List of IP/network, separated with spaces, to put into the whitelist. | -|`WHITELIST_IP_URLS` | |global |no |List of URLs, separated with spaces, containing good IP/network to whitelist. | -|`WHITELIST_RDNS_GLOBAL` |`yes` |multisite|no |Only perform RDNS whitelist checks on global IP addresses. | -|`WHITELIST_RDNS` |`.google.com .googlebot.com .yandex.ru .yandex.net .yandex.com .search.msn.com .baidu.com .baidu.jp .crawl.yahoo.net .fwd.linkedin.com .twitter.com .twttr.com .discord.com` |multisite|no |List of reverse DNS suffixes, separated with spaces, to whitelist. | -|`WHITELIST_RDNS_URLS` | |global |no |List of URLs, separated with spaces, containing reverse DNS suffixes to whitelist.| -|`WHITELIST_ASN` |`32934` |multisite|no |List of ASN numbers, separated with spaces, to whitelist. | -|`WHITELIST_ASN_URLS` | |global |no |List of URLs, separated with spaces, containing ASN to whitelist. | -|`WHITELIST_USER_AGENT` | |multisite|no |List of User-Agent (PCRE regex), separated with spaces, to whitelist. | -|`WHITELIST_USER_AGENT_URLS`| |global |no |List of URLs, separated with spaces, containing good User-Agent to whitelist. | -|`WHITELIST_URI` | |multisite|no |List of URI (PCRE regex), separated with spaces, to whitelist. | -|`WHITELIST_URI_URLS` | |global |no |List of URLs, separated with spaces, containing bad URI to whitelist. | +| Setting | Default | Context |Multiple| Description | +|---------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|--------|----------------------------------------------------------------------------------| +|`USE_WHITELIST` |`yes` |multisite|no |Activate whitelist feature. | +|`WHITELIST_IP` |`20.191.45.212 40.88.21.235 40.76.173.151 40.76.163.7 20.185.79.47 52.142.26.175 20.185.79.15 52.142.24.149 40.76.162.208 40.76.163.23 40.76.162.191 40.76.162.247` |multisite|no |List of IP/network, separated with spaces, to put into the whitelist. | +|`WHITELIST_IP_URLS` | |global |no |List of URLs, separated with spaces, containing good IP/network to whitelist. | +|`WHITELIST_RDNS_GLOBAL` |`yes` |multisite|no |Only perform RDNS whitelist checks on global IP addresses. | +|`WHITELIST_RDNS` |`.google.com .googlebot.com .yandex.ru .yandex.net .yandex.com .search.msn.com .baidu.com .baidu.jp .crawl.yahoo.net .fwd.linkedin.com .twitter.com .twttr.com .discord.com`|multisite|no |List of reverse DNS suffixes, separated with spaces, to whitelist. | +|`WHITELIST_RDNS_URLS` | |global |no |List of URLs, separated with spaces, containing reverse DNS suffixes to whitelist.| +|`WHITELIST_ASN` |`32934` |multisite|no |List of ASN numbers, separated with spaces, to whitelist. | +|`WHITELIST_ASN_URLS` | |global |no |List of URLs, separated with spaces, containing ASN to whitelist. | +|`WHITELIST_USER_AGENT` | |multisite|no |List of User-Agent (PCRE regex), separated with spaces, to whitelist. | +|`WHITELIST_USER_AGENT_URLS`| |global |no |List of URLs, separated with spaces, containing good User-Agent to whitelist. | +|`WHITELIST_URI` | |multisite|no |List of URI (PCRE regex), separated with spaces, to whitelist. | +|`WHITELIST_URI_URLS` | |global |no |List of URLs, separated with spaces, containing bad URI to whitelist. | diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 80e249c98..578c93fd3 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -80,10 +80,10 @@ Here is how you can access the logs, depending on your integration : journalctl -u bunkerweb --no-pager ``` - Common logs are located inside the `/var/log/nginx` directory : + Common logs are located inside the `/var/log/bunkerweb` directory : ```shell - cat /var/log/nginx/error.log - cat /var/log/nginx/access.log + cat /var/log/bunkerweb/error.log + cat /var/log/bunkerweb/access.log ``` === "Ansible" @@ -93,10 +93,10 @@ Here is how you can access the logs, depending on your integration : ansible -i inventory.yml all -a "journalctl -u bunkerweb --no-pager" --become ``` - Common logs are located inside the `/var/log/nginx` directory : + Common logs are located inside the `/var/log/bunkerweb` directory : ```shell - ansible -i inventory.yml all -a "cat /var/log/nginx/error.log" --become - ansible -i inventory.yml all -a "cat /var/log/nginx/access.log" --become + ansible -i inventory.yml all -a "cat /var/log/bunkerweb/error.log" --become + ansible -i inventory.yml all -a "cat /var/log/bunkerweb/access.log" --become ``` === "Vagrant" @@ -106,10 +106,10 @@ Here is how you can access the logs, depending on your integration : journalctl -u bunkerweb --no-pager ``` - Common logs are located inside the `/var/log/nginx` directory : + Common logs are located inside the `/var/log/bunkerweb` directory : ```shell - cat /var/log/nginx/error.log - cat /var/log/nginx/access.log + cat /var/log/bunkerweb/error.log + cat /var/log/bunkerweb/access.log ``` ## Permissions @@ -280,4 +280,8 @@ If you have bots that need to access your website, the recommended way to avoid - Healthcheck / status bot - Callback like IPN or webhook -- Social media crawler \ No newline at end of file +- Social media crawler + +## Timezone + +When using container-based integrations, the timezone of the container may not match the one of the host machine. To resolve that, you can set the `TZ` environment variable to the timezone of your choice on your containers (e.g. `TZ=Europe/Paris`). You will find the list of timezone identifers [here](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List). \ No newline at end of file diff --git a/docs/web-ui.md b/docs/web-ui.md index 886ad11ec..a43af7723 100644 --- a/docs/web-ui.md +++ b/docs/web-ui.md @@ -55,13 +55,12 @@ Because the web UI is a web application, the recommended installation procedure - `ADMIN_USERNAME` : username to access the web UI - `ADMIN_PASSWORD` : password to access the web UI - - `ABSOLUTE_URI` : full URI of your web UI instance (like `http://www.example.com/foo/`) Accessing the web UI through BunkerWeb is a classical [reverse proxy setup](quickstart-guide.md#protect-http-applications). We recommend you to connect BunkerWeb and web UI using a dedicated network (like `bw-universe` also used by the scheduler) so it won't be on the same network of your web services for obvious security reasons. Please note that the web UI container is listening on the `7000` port. !!! info "Database backend" - If you want another Database backend than MariaDB please refer to the docker-compose files in the [misc/integrations folder](https://github.com/bunkerity/bunkerweb/tree/v1.5.0/misc/integrations) of the repository. + If you want another Database backend than MariaDB please refer to the docker-compose files in the [misc/integrations folder](https://github.com/bunkerity/bunkerweb/tree/v1.5.1/misc/integrations) of the repository. Here is the docker-compose boilerplate that you can use (don't forget to edit the `changeme` data) : @@ -70,7 +69,7 @@ Because the web UI is a web application, the recommended installation procedure services: bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -86,16 +85,15 @@ Because the web UI is a web application, the recommended installation procedure - USE_GZIP=yes - www.example.com_USE_UI=yes - www.example.com_USE_REVERSE_PROXY=yes - - www.example.com_REVERSE_PROXY_URL=/changeme/ + - www.example.com_REVERSE_PROXY_URL=/changeme - www.example.com_REVERSE_PROXY_HOST=http://bw-ui:7000 - - www.example.com_REVERSE_PROXY_HEADERS=X-Script-Name /changeme - www.example.com_INTERCEPTED_ERROR_CODES=400 404 405 413 429 500 501 502 503 504 networks: - bw-universe - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - bunkerweb - bw-docker @@ -107,16 +105,17 @@ Because the web UI is a web application, the recommended installation procedure - bw-docker bw-docker: - image: tecnativa/docker-socket-proxy + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker bw-ui: - image: bunkerity/bunkerweb-ui:1.5.0 + image: bunkerity/bunkerweb-ui:1.5.1 depends_on: - bw-docker environment: @@ -124,7 +123,6 @@ Because the web UI is a web application, the recommended installation procedure - DOCKER_HOST=tcp://bw-docker:2375 - ADMIN_USERNAME=changeme - ADMIN_PASSWORD=changeme # Remember to set a stronger password for the changeme user - - ABSOLUTE_URI=http://www.example.com/changeme/ networks: - bw-universe - bw-docker @@ -177,13 +175,12 @@ Because the web UI is a web application, the recommended installation procedure - `ADMIN_USERNAME` : username to access the web UI - `ADMIN_PASSWORD` : password to access the web UI - - `ABSOLUTE_URI` : full URI of your web UI instance (like `http://www.example.com/foo/`) Accessing the web UI through BunkerWeb is a classical [reverse proxy setup](quickstart-guide.md#protect-http-applications). We recommend you to connect BunkerWeb and web UI using a dedicated network (like `bw-universe` also used by the scheduler and autoconf) so it won't be on the same network of your web services for obvious security reasons. Please note that the web UI container is listening on the `7000` port. !!! info "Database backend" - If you want another Database backend than MariaDB please refer to the docker-compose files in the [misc/integrations folder](https://github.com/bunkerity/bunkerweb/tree/v1.5.0/misc/integrations) of the repository. + If you want another Database backend than MariaDB please refer to the docker-compose files in the [misc/integrations folder](https://github.com/bunkerity/bunkerweb/tree/v1.5.1/misc/integrations) of the repository. Here is the docker-compose boilerplate that you can use (don't forget to edit the `changeme` data) : @@ -192,7 +189,7 @@ Because the web UI is a web application, the recommended installation procedure services: bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -209,7 +206,7 @@ Because the web UI is a web application, the recommended installation procedure - bw-services bw-autoconf: - image: bunkerity/bunkerweb-autoconf:1.5.0 + image: bunkerity/bunkerweb-autoconf:1.5.1 depends_on: - bunkerweb - bw-docker @@ -222,7 +219,7 @@ Because the web UI is a web application, the recommended installation procedure - bw-docker bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - bunkerweb - bw-docker @@ -235,11 +232,12 @@ Because the web UI is a web application, the recommended installation procedure - bw-docker bw-docker: - image: tecnativa/docker-socket-proxy + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker @@ -256,7 +254,7 @@ Because the web UI is a web application, the recommended installation procedure - bw-docker bw-ui: - image: bunkerity/bunkerweb-ui:1.5.0 + image: bunkerity/bunkerweb-ui:1.5.1 networks: bw-docker: bw-universe: @@ -268,14 +266,12 @@ Because the web UI is a web application, the recommended installation procedure - AUTOCONF_MODE=yes - ADMIN_USERNAME=admin - ADMIN_PASSWORD=changeme - - ABSOLUTE_URI=http://www.example.com/changeme/ labels: - "bunkerweb.SERVER_NAME=www.example.com" - "bunkerweb.USE_UI=yes" - "bunkerweb.USE_REVERSE_PROXY=yes" - - "bunkerweb.REVERSE_PROXY_URL=/changeme/" + - "bunkerweb.REVERSE_PROXY_URL=/changeme" - "bunkerweb.REVERSE_PROXY_HOST=http://bw-ui:7000" - - "bunkerweb.REVERSE_PROXY_HEADERS=X-Script-Name /changeme" - "bunkerweb.INTERCEPTED_ERROR_CODES=400 404 405 413 429 500 501 502 503 504" volumes: @@ -314,13 +310,12 @@ Because the web UI is a web application, the recommended installation procedure - `ADMIN_USERNAME` : username to access the web UI - `ADMIN_PASSWORD` : password to access the web UI - - `ABSOLUTE_URI` : full URI of your web UI instance (like `http://www.example.com/foo/`) Accessing the web UI through BunkerWeb is a classical [reverse proxy setup](quickstart-guide.md#protect-http-applications). We recommend you to connect BunkerWeb and web UI using a dedicated network (like `bw-universe` also used by the scheduler and autoconf) so it won't be on the same network of your web services for obvious security reasons. Please note that the web UI container is listening on the `7000` port. !!! info "Database backend" - If you want another Database backend than MariaDB please refer to the stack files in the [misc/integrations folder](https://github.com/bunkerity/bunkerweb/tree/v1.5.0/misc/integrations) of the repository. + If you want another Database backend than MariaDB please refer to the stack files in the [misc/integrations folder](https://github.com/bunkerity/bunkerweb/tree/v1.5.1/misc/integrations) of the repository. Here is the stack boilerplate that you can use (don't forget to edit the `changeme` data) : @@ -329,7 +324,7 @@ Because the web UI is a web application, the recommended installation procedure services: bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - published: 80 target: 8080 @@ -359,7 +354,7 @@ Because the web UI is a web application, the recommended installation procedure - "bunkerweb.INSTANCE" bw-autoconf: - image: bunkerity/bunkerweb-autoconf:1.5.0 + image: bunkerity/bunkerweb-autoconf:1.5.1 environment: - SWARM_MODE=yes - DOCKER_HOST=tcp://bw-docker:2375 @@ -369,7 +364,7 @@ Because the web UI is a web application, the recommended installation procedure - bw-docker bw-docker: - image: tecnativa/docker-socket-proxy + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: @@ -378,6 +373,7 @@ Because the web UI is a web application, the recommended installation procedure - SERVICES=1 - SWARM=1 - TASKS=1 + - LOG_LEVEL=warning networks: - bw-docker deploy: @@ -386,7 +382,7 @@ Because the web UI is a web application, the recommended installation procedure - "node.role == manager" bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 environment: - SWARM_MODE=yes - DOCKER_HOST=tcp://bw-docker:2375 @@ -413,13 +409,12 @@ Because the web UI is a web application, the recommended installation procedure - bw-universe bw-ui: - image: bunkerity/bunkerweb-ui:1.5.0 + image: bunkerity/bunkerweb-ui:1.5.1 environment: - DATABASE_URI=mariadb+pymysql://bunkerweb:changeme@bw-db:3306/db # Remember to set a stronger password for the database - DOCKER_HOST=tcp://bw-docker:2375 - ADMIN_USERNAME=changeme - ADMIN_PASSWORD=changeme # Remember to set a stronger password for the changeme user - - ABSOLUTE_URI=http://www.example.com/changeme/ networks: - bw-universe - bw-docker @@ -428,11 +423,10 @@ Because the web UI is a web application, the recommended installation procedure - "bunkerweb.SERVER_NAME=www.example.com" - "bunkerweb.USE_UI=yes" - "bunkerweb.USE_REVERSE_PROXY=yes" - - "bunkerweb.REVERSE_PROXY_URL=/changeme/" + - "bunkerweb.REVERSE_PROXY_URL=/changeme" - "bunkerweb.REVERSE_PROXY_HOST=http://bw-ui:7000" - - "bunkerweb.REVERSE_PROXY_HEADERS=X-Script-Name /changeme" - "bunkerweb.REVERSE_PROXY_INTERCEPT_ERRORS=no" - - "INTERCEPTED_ERROR_CODES=400 404 405 413 429 500 501 502 503 504" + - "bunkerweb.INTERCEPTED_ERROR_CODES=400 404 405 413 429 500 501 502 503 504" volumes: bw-data: @@ -463,13 +457,12 @@ Because the web UI is a web application, the recommended installation procedure - `ADMIN_USERNAME` : username to access the web UI - `ADMIN_PASSWORD` : password to access the web UI - - `ABSOLUTE_URI` : full URI of your web UI instance (like `http://www.example.com/foo/`) Accessing the web UI through BunkerWeb is a classical [reverse proxy setup](quickstart-guide.md#protect-http-applications). Network segmentation between web UI and web services is not covered in this documentation. Please note that the web UI container is listening on the `7000` port. !!! info "Database backend" - If you want another Database backend than MariaDB please refer to the yaml files in the [misc/integrations folder](https://github.com/bunkerity/bunkerweb/tree/v1.5.0/misc/integrations) of the repository. + If you want another Database backend than MariaDB please refer to the yaml files in the [misc/integrations folder](https://github.com/bunkerity/bunkerweb/tree/v1.5.1/misc/integrations) of the repository. Here is the yaml boilerplate that you can use (don't forget to edit the `changeme` data) : @@ -524,7 +517,7 @@ Because the web UI is a web application, the recommended installation procedure containers: # using bunkerweb as name is mandatory - name: bunkerweb - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 imagePullPolicy: Always securityContext: runAsUser: 101 @@ -594,7 +587,7 @@ Because the web UI is a web application, the recommended installation procedure serviceAccountName: sa-bunkerweb containers: - name: bunkerweb-controller - image: bunkerity/bunkerweb-autoconf:1.5.0 + image: bunkerity/bunkerweb-autoconf:1.5.1 imagePullPolicy: Always env: - name: KUBERNETES_MODE @@ -621,7 +614,7 @@ Because the web UI is a web application, the recommended installation procedure serviceAccountName: sa-bunkerweb containers: - name: bunkerweb-scheduler - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 imagePullPolicy: Always env: - name: KUBERNETES_MODE @@ -705,15 +698,13 @@ Because the web UI is a web application, the recommended installation procedure spec: containers: - name: bunkerweb-ui - image: bunkerity/bunkerweb-ui:1.5.0 + image: bunkerity/bunkerweb-ui:1.5.1 imagePullPolicy: Always env: - name: ADMIN_USERNAME value: "changeme" - name: "ADMIN_PASSWORD" value: "changeme" - - name: "ABSOLUTE_URI" - value: "http://www.example.com/changeme/" - name: KUBERNETES_MODE value: "YES" - name: "DATABASE_URI" @@ -788,14 +779,14 @@ Because the web UI is a web application, the recommended installation procedure name: ingress annotations: bunkerweb.io/www.example.com_USE_UI: "yes" - bunkerweb.io/www.example.com_REVERSE_PROXY_HEADERS_1: "X-Script-Name /changeme" bunkerweb.io/www.example.com_REVERSE_PROXY_INTERCEPT_ERRORS: "no" + bunkerweb.io/www.example.com_INTERCEPTED_ERROR_CODES: '400 404 405 413 429 500 501 502 503 504' spec: rules: - host: www.example.com http: paths: - - path: /changeme/ + - path: /changeme pathType: Prefix backend: service: @@ -819,7 +810,6 @@ Because the web UI is a web application, the recommended installation procedure ```conf ADMIN_USERNAME=changeme ADMIN_PASSWORD=changeme - ABSOLUTE_URI=http://www.example.com/changeme/ ``` Each time you edit the `/etc/bunkerweb/ui.env` file, you will need to restart the service : @@ -841,9 +831,8 @@ Because the web UI is a web application, the recommended installation procedure MULTISITE=yes www.example.com_USE_UI=yes www.example.com_USE_REVERSE_PROXY=yes - www.example.com_REVERSE_PROXY_URL=/changeme/ + www.example.com_REVERSE_PROXY_URL=/changeme www.example.com_REVERSE_PROXY_HOST=http://127.0.0.1:7000 - www.example.com_REVERSE_PROXY_HEADERS=X-Script-Name /changeme www.example.com_INTERCEPTED_ERROR_CODES=400 404 405 413 429 500 501 502 503 504 ``` @@ -862,7 +851,6 @@ Because the web UI is a web application, the recommended installation procedure ```conf ADMIN_USERNAME=changeme ADMIN_PASSWORD=changeme - ABSOLUTE_URI=http://www.example.com/changeme/ ``` Here is the `my_variables.env` boilerplate you can use : @@ -875,9 +863,8 @@ Because the web UI is a web application, the recommended installation procedure MULTISITE=yes www.example.com_USE_UI=yes www.example.com_USE_REVERSE_PROXY=yes - www.example.com_REVERSE_PROXY_URL=/changeme/ + www.example.com_REVERSE_PROXY_URL=/changeme www.example.com_REVERSE_PROXY_HOST=http://127.0.0.1:7000 - www.example.com_REVERSE_PROXY_HEADERS=X-Script-Name /changeme www.example.com_INTERCEPTED_ERROR_CODES=400 404 405 413 429 500 501 502 503 504 ``` @@ -929,7 +916,6 @@ Because the web UI is a web application, the recommended installation procedure ```conf ADMIN_USERNAME=changeme ADMIN_PASSWORD=changeme - ABSOLUTE_URI=http://www.example.com/changeme/ ``` Each time you edit the `/etc/bunkerweb/ui.env` file, you will need to restart the service : @@ -950,9 +936,8 @@ Because the web UI is a web application, the recommended installation procedure MULTISITE=yes www.example.com_USE_UI=yes www.example.com_USE_REVERSE_PROXY=yes - www.example.com_REVERSE_PROXY_URL=/changeme/ + www.example.com_REVERSE_PROXY_URL=/changeme www.example.com_REVERSE_PROXY_HOST=http://127.0.0.1:7000 - www.example.com_REVERSE_PROXY_HEADERS=X-Script-Name /changeme www.example.com_INTERCEPTED_ERROR_CODES=400 404 405 413 429 500 501 502 503 504 ``` diff --git a/examples/authelia/docker-compose.yml b/examples/authelia/docker-compose.yml index 3f2afe2b1..91602de0d 100644 --- a/examples/authelia/docker-compose.yml +++ b/examples/authelia/docker-compose.yml @@ -2,7 +2,7 @@ version: "3.4" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -44,7 +44,7 @@ services: - app2.example.com_REVERSE_PROXY_HEADERS=Remote-User $$user;Remote-Groups $$groups;Remote-Name $$name;Remote-Email $$email bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -56,11 +56,12 @@ services: - bw-data:/data bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/examples/authelia/tests.json b/examples/authelia/tests.json index 0b5245f9b..edb0fd9d6 100644 --- a/examples/authelia/tests.json +++ b/examples/authelia/tests.json @@ -1,7 +1,7 @@ { "name": "authelia", "kinds": ["docker", "autoconf", "swarm", "linux"], - "timeout": 60, + "timeout": 120, "delay": 60, "tests": [ { diff --git a/examples/authentik/docker-compose.yml b/examples/authentik/docker-compose.yml index 5efadbaaa..11a903c23 100644 --- a/examples/authentik/docker-compose.yml +++ b/examples/authentik/docker-compose.yml @@ -2,7 +2,7 @@ version: "3.4" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -53,7 +53,7 @@ services: - app2.example.com_REVERSE_PROXY_HEADERS=X-authentik-username $$authentik_username;X-authentik-groups $$authentik_groups;X-authentik-email $$authentik_email;X-authentik-name $$authentik_name;X-authentik-uid $$authentik_uid bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -65,11 +65,12 @@ services: - bw-data:/data bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/examples/behind-reverse-proxy/docker-compose.yml b/examples/behind-reverse-proxy/docker-compose.yml index 0c0cbb64a..ad6273363 100644 --- a/examples/behind-reverse-proxy/docker-compose.yml +++ b/examples/behind-reverse-proxy/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 environment: - SERVER_NAME=www.example.com # replace with your domains - API_WHITELIST_IP=127.0.0.0/8 10.20.30.0/24 @@ -24,7 +24,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -36,11 +36,12 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/examples/bigbluebutton/docker-compose.yml b/examples/bigbluebutton/docker-compose.yml index 615389ce2..264bf1b78 100644 --- a/examples/bigbluebutton/docker-compose.yml +++ b/examples/bigbluebutton/docker-compose.yml @@ -27,7 +27,7 @@ services: ... mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -50,7 +50,7 @@ services: bw-universe: bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -62,11 +62,12 @@ services: bw-docker: bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/examples/certbot-dns-cloudflare/docker-compose.yml b/examples/certbot-dns-cloudflare/docker-compose.yml index eb2e03eee..145d81e42 100644 --- a/examples/certbot-dns-cloudflare/docker-compose.yml +++ b/examples/certbot-dns-cloudflare/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -17,9 +17,9 @@ services: - USE_CLIENT_CACHE=yes - USE_GZIP=yes - USE_REVERSE_PROXY=yes - - USE_CUSTOM_HTTPS=yes - - CUSTOM_HTTPS_CERT=/certs/live/example.com/fullchain.pem - - CUSTOM_HTTPS_KEY=/certs/live/example.com/privkey.pem + - USE_CUSTOM_SSL=yes + - CUSTOM_SSL_CERT=/certs/live/example.com/fullchain.pem + - CUSTOM_SSL_KEY=/certs/live/example.com/privkey.pem - app1.example.com_REVERSE_PROXY_URL=/ - app1.example.com_REVERSE_PROXY_HOST=http://app1 - app2.example.com_REVERSE_PROXY_URL=/ @@ -33,7 +33,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -46,11 +46,12 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/examples/certbot-dns-digitalocean/docker-compose.yml b/examples/certbot-dns-digitalocean/docker-compose.yml index d0f363e74..ee1ea2aa1 100644 --- a/examples/certbot-dns-digitalocean/docker-compose.yml +++ b/examples/certbot-dns-digitalocean/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -17,9 +17,9 @@ services: - USE_CLIENT_CACHE=yes - USE_GZIP=yes - USE_REVERSE_PROXY=yes - - USE_CUSTOM_HTTPS=yes - - CUSTOM_HTTPS_CERT=/certs/live/example.com/fullchain.pem - - CUSTOM_HTTPS_KEY=/certs/live/example.com/privkey.pem + - USE_CUSTOM_SSL=yes + - CUSTOM_SSL_CERT=/certs/live/example.com/fullchain.pem + - CUSTOM_SSL_KEY=/certs/live/example.com/privkey.pem - app1.example.com_REVERSE_PROXY_URL=/ - app1.example.com_REVERSE_PROXY_HOST=http://app1 - app2.example.com_REVERSE_PROXY_URL=/ @@ -33,7 +33,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -46,11 +46,12 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/examples/certbot-dns-google/docker-compose.yml b/examples/certbot-dns-google/docker-compose.yml index 56bdff380..4b65b4801 100644 --- a/examples/certbot-dns-google/docker-compose.yml +++ b/examples/certbot-dns-google/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -17,9 +17,9 @@ services: - USE_CLIENT_CACHE=yes - USE_GZIP=yes - USE_REVERSE_PROXY=yes - - USE_CUSTOM_HTTPS=yes - - CUSTOM_HTTPS_CERT=/certs/live/example.com/fullchain.pem - - CUSTOM_HTTPS_KEY=/certs/live/example.com/privkey.pem + - USE_CUSTOM_SSL=yes + - CUSTOM_SSL_CERT=/certs/live/example.com/fullchain.pem + - CUSTOM_SSL_KEY=/certs/live/example.com/privkey.pem - app1.example.com_REVERSE_PROXY_URL=/ - app1.example.com_REVERSE_PROXY_HOST=http://app1 - app2.example.com_REVERSE_PROXY_URL=/ @@ -33,7 +33,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -46,11 +46,12 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/examples/certbot-dns-ovh/docker-compose.yml b/examples/certbot-dns-ovh/docker-compose.yml index e6fbe6885..69963d5ca 100644 --- a/examples/certbot-dns-ovh/docker-compose.yml +++ b/examples/certbot-dns-ovh/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -17,9 +17,9 @@ services: - USE_CLIENT_CACHE=yes - USE_GZIP=yes - USE_REVERSE_PROXY=yes - - USE_CUSTOM_HTTPS=yes - - CUSTOM_HTTPS_CERT=/certs/live/example.com/fullchain.pem - - CUSTOM_HTTPS_KEY=/certs/live/example.com/privkey.pem + - USE_CUSTOM_SSL=yes + - CUSTOM_SSL_CERT=/certs/live/example.com/fullchain.pem + - CUSTOM_SSL_KEY=/certs/live/example.com/privkey.pem - app1.example.com_REVERSE_PROXY_URL=/ - app1.example.com_REVERSE_PROXY_HOST=http://app1 - app2.example.com_REVERSE_PROXY_URL=/ @@ -33,7 +33,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -46,11 +46,12 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/examples/certbot-dns-route53/docker-compose.yml b/examples/certbot-dns-route53/docker-compose.yml index 7c1f901ea..aea2ec5dd 100644 --- a/examples/certbot-dns-route53/docker-compose.yml +++ b/examples/certbot-dns-route53/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -17,9 +17,9 @@ services: - USE_CLIENT_CACHE=yes - USE_GZIP=yes - USE_REVERSE_PROXY=yes - - USE_CUSTOM_HTTPS=yes - - CUSTOM_HTTPS_CERT=/certs/live/example.com/fullchain.pem - - CUSTOM_HTTPS_KEY=/certs/live/example.com/privkey.pem + - USE_CUSTOM_SSL=yes + - CUSTOM_SSL_CERT=/certs/live/example.com/fullchain.pem + - CUSTOM_SSL_KEY=/certs/live/example.com/privkey.pem - app1.example.com_REVERSE_PROXY_URL=/ - app1.example.com_REVERSE_PROXY_HOST=http://app1 - app2.example.com_REVERSE_PROXY_URL=/ @@ -33,7 +33,7 @@ services: - bw-services bbw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -46,11 +46,12 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/examples/cors/docker-compose.yml b/examples/cors/docker-compose.yml index 22cefbdd4..ab1cf9958 100644 --- a/examples/cors/docker-compose.yml +++ b/examples/cors/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -38,7 +38,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -50,11 +50,12 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker @@ -101,4 +102,4 @@ networks: bw-services: volumes: - bw-data: \ No newline at end of file + bw-data: diff --git a/examples/docker-configs/docker-compose.yml b/examples/docker-configs/docker-compose.yml index 2ab2ad0ed..39cdaf770 100644 --- a/examples/docker-configs/docker-compose.yml +++ b/examples/docker-configs/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -53,7 +53,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -65,11 +65,12 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/examples/docker-configs/tests.json b/examples/docker-configs/tests.json index 94f178484..54eb9ee94 100644 --- a/examples/docker-configs/tests.json +++ b/examples/docker-configs/tests.json @@ -1,6 +1,7 @@ { "name": "docker-configs", "kinds": ["docker"], + "delay": 30, "timeout": 60, "tests": [ { diff --git a/examples/drupal/autoconf.yml b/examples/drupal/autoconf.yml index f1f4b8475..509cfda9e 100644 --- a/examples/drupal/autoconf.yml +++ b/examples/drupal/autoconf.yml @@ -35,7 +35,7 @@ services: - MYSQL_ROOT_PASSWORD=db-root-pwd # replace with a stronger password - MYSQL_DATABASE=drupaldb - MYSQL_USER=user - - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password + - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password volumes: db-data: diff --git a/examples/drupal/docker-compose.yml b/examples/drupal/docker-compose.yml index 679291eab..6a843d6ed 100644 --- a/examples/drupal/docker-compose.yml +++ b/examples/drupal/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -28,7 +28,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -40,11 +40,12 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker @@ -66,7 +67,7 @@ services: - MYSQL_ROOT_PASSWORD=db-root-pwd # replace with a stronger password - MYSQL_DATABASE=drupaldb - MYSQL_USER=user - - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password + - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password networks: - bw-services diff --git a/examples/drupal/drupal-chart-values.yml b/examples/drupal/drupal-chart-values.yml index 7f105fe7f..896a5e838 100644 --- a/examples/drupal/drupal-chart-values.yml +++ b/examples/drupal/drupal-chart-values.yml @@ -3,4 +3,4 @@ drupalPassword: "changeme42" drupalEmail: "contact@example.com" mariadb: auth: - password: "changeme1337" \ No newline at end of file + password: "changeme1337" diff --git a/examples/drupal/swarm.yml b/examples/drupal/swarm.yml index 7564239c6..b7cbe079a 100644 --- a/examples/drupal/swarm.yml +++ b/examples/drupal/swarm.yml @@ -33,7 +33,7 @@ services: - MYSQL_ROOT_PASSWORD=db-root-pwd # replace with a stronger password - MYSQL_DATABASE=drupaldb - MYSQL_USER=user - - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password + - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password deploy: placement: constraints: diff --git a/examples/ghost/autoconf.yml b/examples/ghost/autoconf.yml index 23264fb2e..492f95ce1 100644 --- a/examples/ghost/autoconf.yml +++ b/examples/ghost/autoconf.yml @@ -24,4 +24,4 @@ volumes: networks: bw-services: external: true - name: bw-services \ No newline at end of file + name: bw-services diff --git a/examples/ghost/docker-compose.yml b/examples/ghost/docker-compose.yml index 29ab2378f..8cd16628e 100644 --- a/examples/ghost/docker-compose.yml +++ b/examples/ghost/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -24,7 +24,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -36,11 +36,12 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/examples/ghost/ghost-chart-values.yml b/examples/ghost/ghost-chart-values.yml index f9b7b6f5c..bb48fe096 100644 --- a/examples/ghost/ghost-chart-values.yml +++ b/examples/ghost/ghost-chart-values.yml @@ -3,4 +3,4 @@ ghostPassword: "changeme42" ghostHost: "www.example.com" mysql: auth: - password: "changeme1337" \ No newline at end of file + password: "changeme1337" diff --git a/examples/gogs/docker-compose.yml b/examples/gogs/docker-compose.yml index df6a0e57d..96d3c7817 100644 --- a/examples/gogs/docker-compose.yml +++ b/examples/gogs/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -28,7 +28,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -40,11 +40,12 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/examples/hardened/docker-compose.yml b/examples/hardened/docker-compose.yml index dac0b84c7..c7441222c 100644 --- a/examples/hardened/docker-compose.yml +++ b/examples/hardened/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 # dropping all capabilities cap_drop: - ALL @@ -15,6 +15,7 @@ services: tmpfs: - /tmp:mode=0770,uid=0,gid=101 - /var/tmp/bunkerweb:mode=0770,uid=0,gid=101 + - /var/run/bunkerweb:mode=0770,uid=0,gid=101 - /var/cache/bunkerweb:mode=0770,uid=0,gid=101 - /etc/nginx:mode=0770,uid=0,gid=101 ports: @@ -38,7 +39,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -50,11 +51,12 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/examples/joomla/autoconf.yml b/examples/joomla/autoconf.yml index 173b77d55..766d66877 100644 --- a/examples/joomla/autoconf.yml +++ b/examples/joomla/autoconf.yml @@ -36,7 +36,7 @@ services: - MYSQL_ROOT_PASSWORD=db-root-pwd # replace with a stronger password - MYSQL_DATABASE=joomla_db - MYSQL_USER=user - - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match JOOMLA_DB_PASSWORD) + - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match JOOMLA_DB_PASSWORD) volumes: joomla-data: diff --git a/examples/joomla/docker-compose.yml b/examples/joomla/docker-compose.yml index 522b10294..24a43b8b0 100644 --- a/examples/joomla/docker-compose.yml +++ b/examples/joomla/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -28,7 +28,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -40,11 +40,12 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker @@ -68,7 +69,7 @@ services: - MYSQL_ROOT_PASSWORD=db-root-pwd # replace with a stronger password - MYSQL_DATABASE=joomla_db - MYSQL_USER=user - - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match JOOMLA_DB_PASSWORD) + - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match JOOMLA_DB_PASSWORD) networks: - bw-services volumes: diff --git a/examples/joomla/joomla-chart-values.yml b/examples/joomla/joomla-chart-values.yml index eb1d42965..07f14e1f1 100644 --- a/examples/joomla/joomla-chart-values.yml +++ b/examples/joomla/joomla-chart-values.yml @@ -3,4 +3,4 @@ joomlaPassword: "changeme42" joomlaEmail: "contact@example.com" mariadb: auth: - password: "changeme1337" \ No newline at end of file + password: "changeme1337" diff --git a/examples/joomla/swarm.yml b/examples/joomla/swarm.yml index 782704316..c69331651 100644 --- a/examples/joomla/swarm.yml +++ b/examples/joomla/swarm.yml @@ -36,13 +36,12 @@ services: - MYSQL_ROOT_PASSWORD=db-root-pwd # replace with a stronger password - MYSQL_DATABASE=joomla_db - MYSQL_USER=user - - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match JOOMLA_DB_PASSWORD) + - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match JOOMLA_DB_PASSWORD) deploy: placement: constraints: - "node.role==worker" - networks: bw-services: external: true diff --git a/examples/load-balancer/docker-compose.yml b/examples/load-balancer/docker-compose.yml index 4f91602aa..750471473 100644 --- a/examples/load-balancer/docker-compose.yml +++ b/examples/load-balancer/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -31,7 +31,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -43,11 +43,12 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/examples/load-balancer/tests.json b/examples/load-balancer/tests.json index 153467472..a64188350 100644 --- a/examples/load-balancer/tests.json +++ b/examples/load-balancer/tests.json @@ -1,7 +1,7 @@ { "name": "load-balancer", "kinds": ["docker"], - "timeout": 60, + "timeout": 120, "no_copy_container": true, "tests": [ { diff --git a/examples/magento/autoconf.yml b/examples/magento/autoconf.yml index 2b7bb3d59..05912a5fe 100644 --- a/examples/magento/autoconf.yml +++ b/examples/magento/autoconf.yml @@ -55,7 +55,7 @@ services: - MYSQL_ROOT_PASSWORD=db-root-pwd # replace with a stronger password - MYSQL_DATABASE=magentodb - MYSQL_USER=user - - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match MAGENTO_DATABASE_PASSWORD) + - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match MAGENTO_DATABASE_PASSWORD) volumes: magento-data: diff --git a/examples/magento/docker-compose.yml b/examples/magento/docker-compose.yml index d96f70775..cf2fd690f 100644 --- a/examples/magento/docker-compose.yml +++ b/examples/magento/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -29,7 +29,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -41,11 +41,12 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker @@ -85,7 +86,7 @@ services: - MYSQL_ROOT_PASSWORD=db-root-pwd # replace with a stronger password - MYSQL_DATABASE=magentodb - MYSQL_USER=user - - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match MAGENTO_DATABASE_PASSWORD) + - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match MAGENTO_DATABASE_PASSWORD) networks: - bw-services diff --git a/examples/magento/magento-chart-values.yml b/examples/magento/magento-chart-values.yml index d65ff2d17..3be28f4b6 100644 --- a/examples/magento/magento-chart-values.yml +++ b/examples/magento/magento-chart-values.yml @@ -7,4 +7,4 @@ magentoLastName: "Doe" magentoAdminUri: "admin" mariadb: auth: - password: "changeme1337" \ No newline at end of file + password: "changeme1337" diff --git a/examples/magento/swarm.yml b/examples/magento/swarm.yml index 61eb26485..3178cfa1e 100644 --- a/examples/magento/swarm.yml +++ b/examples/magento/swarm.yml @@ -50,7 +50,7 @@ services: - MYSQL_ROOT_PASSWORD=db-root-pwd # replace with a stronger password - MYSQL_DATABASE=magentodb - MYSQL_USER=user - - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match MAGENTO_DATABASE_PASSWORD) + - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match MAGENTO_DATABASE_PASSWORD) deploy: placement: constraints: diff --git a/examples/mattermost/docker-compose.yml b/examples/mattermost/docker-compose.yml index d32b439cf..e4b7cf1e9 100644 --- a/examples/mattermost/docker-compose.yml +++ b/examples/mattermost/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -44,7 +44,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -56,11 +56,12 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/examples/mongo-express/docker-compose.yml b/examples/mongo-express/docker-compose.yml index 35ee63dfc..1be9fa0f0 100644 --- a/examples/mongo-express/docker-compose.yml +++ b/examples/mongo-express/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -27,7 +27,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -39,11 +39,12 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/examples/moodle/autoconf.yml b/examples/moodle/autoconf.yml index f9c5cedd6..0748d5089 100644 --- a/examples/moodle/autoconf.yml +++ b/examples/moodle/autoconf.yml @@ -13,10 +13,10 @@ services: - moodle-files:/bitnami/moodle - moodle-data:/bitnami/moodledata environment: - - MOODLE_USERNAME=admin # replace with your moodle admin username - - MOODLE_PASSWORD=password # replace with your moodle admin password - - MOODLE_EMAIL=moodle@example.com # replace with your moodle admin email - - MOODLE_SITE_NAME=My Moodle # replace with your moodle site name + - MOODLE_USERNAME=admin # replace with your moodle admin username + - MOODLE_PASSWORD=password # replace with your moodle admin password + - MOODLE_EMAIL=moodle@example.com # replace with your moodle admin email + - MOODLE_SITE_NAME=My Moodle # replace with your moodle site name - MOODLE_DATABASE_HOST=mydb - MOODLE_DATABASE_NAME=moodle - MOODLE_DATABASE_USER=user @@ -36,10 +36,10 @@ services: aliases: - mydb environment: - - MYSQL_ROOT_PASSWORD=db-root-pwd # replace with a stronger password + - MYSQL_ROOT_PASSWORD=db-root-pwd # replace with a stronger password - MYSQL_DATABASE=moodle - MYSQL_USER=user - - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match MOODLE_DATABASE_PASSWORD) + - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match MOODLE_DATABASE_PASSWORD) - MARIADB_CHARACTER_SET=utf8mb4 - MARIADB_COLLATE=utf8mb4_unicode_ci diff --git a/examples/moodle/docker-compose.yml b/examples/moodle/docker-compose.yml index e55004575..c4204e7b5 100644 --- a/examples/moodle/docker-compose.yml +++ b/examples/moodle/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -25,7 +25,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -37,11 +37,12 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker @@ -53,10 +54,10 @@ services: - moodle-files:/bitnami/moodle - moodle-data:/bitnami/moodledata environment: - - MOODLE_USERNAME=admin # replace with your moodle admin username - - MOODLE_PASSWORD=password # replace with your moodle admin password - - MOODLE_EMAIL=moodle@example.com # replace with your moodle admin email - - MOODLE_SITE_NAME=My Moodle # replace with your moodle site name + - MOODLE_USERNAME=admin # replace with your moodle admin username + - MOODLE_PASSWORD=password # replace with your moodle admin password + - MOODLE_EMAIL=moodle@example.com # replace with your moodle admin email + - MOODLE_SITE_NAME=My Moodle # replace with your moodle site name - MOODLE_DATABASE_HOST=mydb - MOODLE_DATABASE_NAME=moodle - MOODLE_DATABASE_USER=user @@ -69,10 +70,10 @@ services: volumes: - db-data:/var/lib/mysql environment: - - MYSQL_ROOT_PASSWORD=db-root-pwd # replace with a stronger password + - MYSQL_ROOT_PASSWORD=db-root-pwd # replace with a stronger password - MYSQL_DATABASE=moodle - MYSQL_USER=user - - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match MOODLE_DATABASE_PASSWORD) + - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match MOODLE_DATABASE_PASSWORD) - MARIADB_CHARACTER_SET=utf8mb4 - MARIADB_COLLATE=utf8mb4_unicode_ci networks: diff --git a/examples/moodle/moodle-chart-values.yml b/examples/moodle/moodle-chart-values.yml index b4597275d..3a93c2b67 100644 --- a/examples/moodle/moodle-chart-values.yml +++ b/examples/moodle/moodle-chart-values.yml @@ -4,4 +4,4 @@ moodlePassword: "changeme42" moodleEmail: "admin@example.com" mariadb: auth: - password: "changeme1337" \ No newline at end of file + password: "changeme1337" diff --git a/examples/moodle/swarm.yml b/examples/moodle/swarm.yml index cf078434b..fe4b2a06a 100644 --- a/examples/moodle/swarm.yml +++ b/examples/moodle/swarm.yml @@ -36,10 +36,10 @@ services: networks: - bw-services environment: - - MYSQL_ROOT_PASSWORD=db-root-pwd # replace with a stronger password + - MYSQL_ROOT_PASSWORD=db-root-pwd # replace with a stronger password - MYSQL_DATABASE=moodle - MYSQL_USER=user - - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match MOODLE_DATABASE_PASSWORD) + - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match MOODLE_DATABASE_PASSWORD) - MARIADB_CHARACTER_SET=utf8mb4 - MARIADB_COLLATE=utf8mb4_unicode_ci deploy: diff --git a/examples/nextcloud/autoconf.yml b/examples/nextcloud/autoconf.yml index ab7d6595f..35485e314 100644 --- a/examples/nextcloud/autoconf.yml +++ b/examples/nextcloud/autoconf.yml @@ -56,7 +56,6 @@ services: bunkerweb.CUSTOM_CONF_MODSEC_nextcloud= SecRule REQUEST_FILENAME "@rx ^/remote.php/dav/files/" "id:2000,ctl:ruleRemoveByTag=attack-protocol,ctl:ruleRemoveByTag=attack-generic,nolog" - mydb: image: mariadb command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW @@ -70,7 +69,7 @@ services: - MYSQL_ROOT_PASSWORD=db-root-pwd # replace with a stronger password - MYSQL_DATABASE=nc - MYSQL_USER=user - - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match MYSQL_PASSWORD) + - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match MYSQL_PASSWORD) volumes: nc-files: diff --git a/examples/nextcloud/docker-compose.yml b/examples/nextcloud/docker-compose.yml index 781c3806a..d1165a347 100644 --- a/examples/nextcloud/docker-compose.yml +++ b/examples/nextcloud/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -54,7 +54,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -66,11 +66,12 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker @@ -110,7 +111,6 @@ volumes: db-data: nc-files: - networks: bw-universe: ipam: diff --git a/examples/nextcloud/swarm.yml b/examples/nextcloud/swarm.yml index 8fb87729f..3bed05364 100644 --- a/examples/nextcloud/swarm.yml +++ b/examples/nextcloud/swarm.yml @@ -48,7 +48,7 @@ services: - MYSQL_ROOT_PASSWORD=db-root-pwd # replace with a stronger password - MYSQL_DATABASE=nc - MYSQL_USER=user - - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match MYSQL_PASSWORD) + - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match MYSQL_PASSWORD) deploy: placement: constraints: diff --git a/examples/passbolt/autoconf.yml b/examples/passbolt/autoconf.yml index 9182fae77..3e349b57a 100644 --- a/examples/passbolt/autoconf.yml +++ b/examples/passbolt/autoconf.yml @@ -13,7 +13,7 @@ services: environment: - APP_FULL_BASE_URL=https://www.example.com # replace with your URL - DATASOURCES_DEFAULT_HOST=mydb - - DATASOURCES_DEFAULT_PASSWORD=db-user-pwd # replace with a stronger password (must match MYSQL_PASSWORD) + - DATASOURCES_DEFAULT_PASSWORD=db-user-pwd # replace with a stronger password (must match MYSQL_PASSWORD) - DATASOURCES_DEFAULT_USERNAME=user - DATASOURCES_DEFAULT_DATABASE=passbolt volumes: @@ -45,10 +45,10 @@ services: aliases: - mydb environment: - - MYSQL_ROOT_PASSWORD=db-root-pwd # replace with a stronger password + - MYSQL_ROOT_PASSWORD=db-root-pwd # replace with a stronger password - MYSQL_DATABASE=passbolt - MYSQL_USER=user - - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match DATASOURCES_DEFAULT_PASSWORD) + - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match DATASOURCES_DEFAULT_PASSWORD) volumes: gpg-data: diff --git a/examples/passbolt/docker-compose.yml b/examples/passbolt/docker-compose.yml index 9854e02ba..d43362bb5 100644 --- a/examples/passbolt/docker-compose.yml +++ b/examples/passbolt/docker-compose.yml @@ -2,12 +2,12 @@ version: "3" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 environment: - - SERVER_NAME=www.example.com # replace with your domain + - SERVER_NAME=www.example.com # replace with your domain - API_WHITELIST_IP=127.0.0.0/8 10.20.30.0/24 - AUTO_LETS_ENCRYPT=yes - DISABLE_DEFAULT_SERVER=yes @@ -26,7 +26,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -38,11 +38,12 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker @@ -58,7 +59,7 @@ services: environment: - APP_FULL_BASE_URL=https://www.example.com # replace with your URL - DATASOURCES_DEFAULT_HOST=mydb - - DATASOURCES_DEFAULT_PASSWORD=db-user-pwd # replace with a stronger password (must match MYSQL_PASSWORD) + - DATASOURCES_DEFAULT_PASSWORD=db-user-pwd # replace with a stronger password (must match MYSQL_PASSWORD) - DATASOURCES_DEFAULT_USERNAME=user - DATASOURCES_DEFAULT_DATABASE=passbolt volumes: @@ -81,10 +82,10 @@ services: volumes: - db-data:/var/lib/mysql environment: - - MYSQL_ROOT_PASSWORD=db-root-pwd # replace with a stronger password + - MYSQL_ROOT_PASSWORD=db-root-pwd # replace with a stronger password - MYSQL_DATABASE=passbolt - MYSQL_USER=user - - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match DATASOURCES_DEFAULT_PASSWORD) + - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match DATASOURCES_DEFAULT_PASSWORD) networks: - bw-services diff --git a/examples/passbolt/swarm.yml b/examples/passbolt/swarm.yml index 39c27661f..090277c5a 100644 --- a/examples/passbolt/swarm.yml +++ b/examples/passbolt/swarm.yml @@ -11,7 +11,7 @@ services: environment: - APP_FULL_BASE_URL=https://www.example.com # replace with your URL - DATASOURCES_DEFAULT_HOST=mydb - - DATASOURCES_DEFAULT_PASSWORD=db-user-pwd # replace with a stronger password (must match MYSQL_PASSWORD) + - DATASOURCES_DEFAULT_PASSWORD=db-user-pwd # replace with a stronger password (must match MYSQL_PASSWORD) - DATASOURCES_DEFAULT_USERNAME=user - DATASOURCES_DEFAULT_DATABASE=passbolt volumes: @@ -45,10 +45,10 @@ services: networks: - bw-services environment: - - MYSQL_ROOT_PASSWORD=db-root-pwd # replace with a stronger password + - MYSQL_ROOT_PASSWORD=db-root-pwd # replace with a stronger password - MYSQL_DATABASE=passbolt - MYSQL_USER=user - - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match DATASOURCES_DEFAULT_PASSWORD) + - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match DATASOURCES_DEFAULT_PASSWORD) deploy: placement: constraints: diff --git a/examples/php-cookie-flags/docker-compose.yml b/examples/php-cookie-flags/docker-compose.yml index b5227e22a..3ddd6ce7a 100644 --- a/examples/php-cookie-flags/docker-compose.yml +++ b/examples/php-cookie-flags/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -31,7 +31,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -43,11 +43,12 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker @@ -65,7 +66,6 @@ services: volumes: bw-data: - networks: bw-universe: ipam: diff --git a/examples/php-multisite/docker-compose.yml b/examples/php-multisite/docker-compose.yml index b41f75939..6a7511435 100644 --- a/examples/php-multisite/docker-compose.yml +++ b/examples/php-multisite/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -34,7 +34,7 @@ services: - net-app2 bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -46,11 +46,12 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/examples/php-singlesite/docker-compose.yml b/examples/php-singlesite/docker-compose.yml index 89ebaf9b2..04aa557a3 100644 --- a/examples/php-singlesite/docker-compose.yml +++ b/examples/php-singlesite/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -30,7 +30,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -42,11 +42,12 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/examples/prestashop/docker-compose.yml b/examples/prestashop/docker-compose.yml index 4aa1b446d..5986f51ed 100644 --- a/examples/prestashop/docker-compose.yml +++ b/examples/prestashop/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -28,7 +28,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -40,11 +40,12 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/examples/prestashop/prestashop-chart-values.yml b/examples/prestashop/prestashop-chart-values.yml index d476d39ed..7c2b309c5 100644 --- a/examples/prestashop/prestashop-chart-values.yml +++ b/examples/prestashop/prestashop-chart-values.yml @@ -10,4 +10,4 @@ service: type: ClusterIP mariadb: auth: - password: "changeme1337" \ No newline at end of file + password: "changeme1337" diff --git a/examples/proxy-protocol/docker-compose.yml b/examples/proxy-protocol/docker-compose.yml index 2d5cafdd2..31f3e8dbc 100644 --- a/examples/proxy-protocol/docker-compose.yml +++ b/examples/proxy-protocol/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 environment: - SERVER_NAME=www.example.com # replace with your domains - API_WHITELIST_IP=127.0.0.0/8 10.20.30.0/24 @@ -27,7 +27,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -39,11 +39,12 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/examples/radarr/docker-compose.yml b/examples/radarr/docker-compose.yml index 1eed50fc7..0e4381064 100644 --- a/examples/radarr/docker-compose.yml +++ b/examples/radarr/docker-compose.yml @@ -2,7 +2,7 @@ version: "3.5" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -34,7 +34,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -46,11 +46,12 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/examples/radarr/tests.json b/examples/radarr/tests.json index 2fea890ed..763183c9c 100644 --- a/examples/radarr/tests.json +++ b/examples/radarr/tests.json @@ -1,6 +1,7 @@ { "name": "radarr", "kinds": ["docker", "autoconf", "swarm"], + "delay": 180, "timeout": 60, "tests": [ { diff --git a/examples/redmine/autoconf.yml b/examples/redmine/autoconf.yml index ba3352972..d71898cfa 100644 --- a/examples/redmine/autoconf.yml +++ b/examples/redmine/autoconf.yml @@ -33,7 +33,7 @@ services: - MYSQL_ROOT_PASSWORD=db-root-pwd # replace with a stronger password - MYSQL_DATABASE=redminedb - MYSQL_USER=user - - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match REDMINE_DB_PASSWORD) + - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match REDMINE_DB_PASSWORD) volumes: redmine-data: diff --git a/examples/redmine/docker-compose.yml b/examples/redmine/docker-compose.yml index f83d2992b..ce7693b5d 100644 --- a/examples/redmine/docker-compose.yml +++ b/examples/redmine/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -24,7 +24,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -36,11 +36,12 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker @@ -65,7 +66,7 @@ services: - MYSQL_ROOT_PASSWORD=db-root-pwd # replace with a stronger password - MYSQL_DATABASE=redminedb - MYSQL_USER=user - - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match REDMINE_DB_PASSWORD) + - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match REDMINE_DB_PASSWORD) networks: - bw-universe - bw-services diff --git a/examples/redmine/redmine-chart-values.yml b/examples/redmine/redmine-chart-values.yml index b5311f6a5..8698d85b6 100644 --- a/examples/redmine/redmine-chart-values.yml +++ b/examples/redmine/redmine-chart-values.yml @@ -6,4 +6,4 @@ service: type: ClusterIP mariadb: auth: - password: "changeme1337" \ No newline at end of file + password: "changeme1337" diff --git a/examples/redmine/swarm.yml b/examples/redmine/swarm.yml index 9475d356a..5c789c265 100644 --- a/examples/redmine/swarm.yml +++ b/examples/redmine/swarm.yml @@ -33,7 +33,7 @@ services: - MYSQL_ROOT_PASSWORD=db-root-pwd # replace with a stronger password - MYSQL_DATABASE=redminedb - MYSQL_USER=user - - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match REDMINE_DB_PASSWORD) + - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match REDMINE_DB_PASSWORD) deploy: placement: constraints: diff --git a/examples/reverse-proxy-multisite/docker-compose.yml b/examples/reverse-proxy-multisite/docker-compose.yml index b72cf5de9..7883420ab 100644 --- a/examples/reverse-proxy-multisite/docker-compose.yml +++ b/examples/reverse-proxy-multisite/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -27,7 +27,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -39,11 +39,12 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/examples/reverse-proxy-multisite/tests.json b/examples/reverse-proxy-multisite/tests.json index 07fdaf420..9ab43153e 100644 --- a/examples/reverse-proxy-multisite/tests.json +++ b/examples/reverse-proxy-multisite/tests.json @@ -2,7 +2,7 @@ "name": "reverse-proxy-multisite", "kinds": ["docker", "autoconf", "swarm", "kubernetes", "linux"], "timeout": 60, - "delay": 60, + "delay": 90, "tests": [ { "type": "string", diff --git a/examples/reverse-proxy-singlesite/docker-compose.yml b/examples/reverse-proxy-singlesite/docker-compose.yml index 6ea2cf0fc..e23dd3728 100644 --- a/examples/reverse-proxy-singlesite/docker-compose.yml +++ b/examples/reverse-proxy-singlesite/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -32,7 +32,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -44,11 +44,12 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/examples/reverse-proxy-singlesite/tests.json b/examples/reverse-proxy-singlesite/tests.json index c37b0090d..f52f139d1 100644 --- a/examples/reverse-proxy-singlesite/tests.json +++ b/examples/reverse-proxy-singlesite/tests.json @@ -1,6 +1,7 @@ { "name": "reverse-proxy-singlesite", "kinds": ["docker", "autoconf", "swarm", "linux"], + "delay": 120, "timeout": 60, "no_copy_container": true, "tests": [ diff --git a/examples/reverse-proxy-websocket/docker-compose.yml b/examples/reverse-proxy-websocket/docker-compose.yml index c364680c5..d72cd6662 100644 --- a/examples/reverse-proxy-websocket/docker-compose.yml +++ b/examples/reverse-proxy-websocket/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -25,7 +25,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -37,11 +37,12 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/examples/stream-multisite/docker-compose.yml b/examples/stream-multisite/docker-compose.yml index b32deab56..a49dd4716 100644 --- a/examples/stream-multisite/docker-compose.yml +++ b/examples/stream-multisite/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 # required to resolve let's encrypt challenges - 10000:10000 # app1 without SSL/TLS @@ -33,7 +33,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -45,23 +45,24 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker app1: image: istio/tcp-echo-server:1.2 - command: [ "9000", "app1" ] + command: ["9000", "app1"] networks: - bw-services app2: image: istio/tcp-echo-server:1.2 - command: [ "9000", "app2" ] + command: ["9000", "app2"] networks: - bw-services diff --git a/examples/syslog/docker-compose.yml b/examples/syslog/docker-compose.yml index b3c3bd21f..dc66ea564 100644 --- a/examples/syslog/docker-compose.yml +++ b/examples/syslog/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 logging: driver: syslog options: @@ -28,7 +28,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 logging: driver: syslog options: @@ -45,11 +45,12 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/examples/tomcat/docker-compose.yml b/examples/tomcat/docker-compose.yml index 3939bf8a1..39a85468e 100644 --- a/examples/tomcat/docker-compose.yml +++ b/examples/tomcat/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -23,7 +23,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -35,11 +35,12 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/examples/tor-hidden-service/docker-compose.yml b/examples/tor-hidden-service/docker-compose.yml index 3baebee71..aa7ffdee3 100644 --- a/examples/tor-hidden-service/docker-compose.yml +++ b/examples/tor-hidden-service/docker-compose.yml @@ -12,7 +12,7 @@ services: - bw-universe mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 environment: - API_WHITELIST_IP=127.0.0.0/8 10.20.30.0/24 # disable common security measures based on IP @@ -34,7 +34,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -46,11 +46,12 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/examples/web-ui/docker-compose.yml b/examples/web-ui/docker-compose.yml index d28cbe1d6..ee6b8e635 100644 --- a/examples/web-ui/docker-compose.yml +++ b/examples/web-ui/docker-compose.yml @@ -2,7 +2,7 @@ version: "3.5" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -17,10 +17,9 @@ services: - www.example.com_USE_UI=yes - www.example.com_SERVE_FILES=no - www.example.com_USE_REVERSE_PROXY=yes - - www.example.com_REVERSE_PROXY_URL=/changeme/ # replace with another url + - www.example.com_REVERSE_PROXY_URL=/changeme # replace with another url - www.example.com_REVERSE_PROXY_HOST=http://bw-ui:7000 - - www.example.com_REVERSE_PROXY_HEADERS=X-Script-Name /changeme # replace with another url - - www.example.com_REVERSE_PROXY_INTERCEPT_ERRORS=no + - www.example.com_INTERCEPTED_ERROR_CODES=400 404 405 413 429 500 501 502 503 504 labels: - "bunkerweb.INSTANCE" networks: @@ -28,7 +27,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -40,11 +39,10 @@ services: - bw-docker bw-ui: - image: bunkerity/bunkerweb-ui:1.5.0 + image: bunkerity/bunkerweb-ui:1.5.1 depends_on: - bw-docker-proxy environment: - - ABSOLUTE_URI=https://www.example.com/changeme/ # replace with another url - DOCKER_HOST=tcp://bw-docker-proxy:2375 - ADMIN_USERNAME=changeme - ADMIN_PASSWORD=changeme # replace with a stronger password @@ -55,11 +53,12 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/examples/wordpress/autoconf.yml b/examples/wordpress/autoconf.yml index 50b3459d2..a5db280b8 100644 --- a/examples/wordpress/autoconf.yml +++ b/examples/wordpress/autoconf.yml @@ -43,7 +43,7 @@ services: - MYSQL_ROOT_PASSWORD=db-root-pwd # replace with a stronger password - MYSQL_DATABASE=wp - MYSQL_USER=user - - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match WORDPRESS_DB_PASSWORD) + - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match WORDPRESS_DB_PASSWORD) volumes: wp-data: diff --git a/examples/wordpress/docker-compose.yml b/examples/wordpress/docker-compose.yml index 7123b8d22..fa4834990 100644 --- a/examples/wordpress/docker-compose.yml +++ b/examples/wordpress/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: mybunker: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -25,7 +25,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - mybunker environment: @@ -37,11 +37,12 @@ services: - bw-docker bw-docker-proxy: - image: tecnativa/docker-socket-proxy:0.1 + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker @@ -66,7 +67,7 @@ services: - MYSQL_ROOT_PASSWORD=db-root-pwd # replace with a stronger password - MYSQL_DATABASE=wp - MYSQL_USER=user - - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match WORDPRESS_DB_PASSWORD) + - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match WORDPRESS_DB_PASSWORD) networks: - bw-services diff --git a/examples/wordpress/setup-kubernetes.sh b/examples/wordpress/setup-kubernetes.sh index a2c88a775..dd13f41a6 100755 --- a/examples/wordpress/setup-kubernetes.sh +++ b/examples/wordpress/setup-kubernetes.sh @@ -1,4 +1,3 @@ #!/bin/bash -helm repo add wordpress https://charts.bitnami.com/bitnami -helm install -f wordpress-chart-values.yml wordpress bitnami/wordpress +helm install -f wordpress-chart-values.yml wordpress oci://registry-1.docker.io/bitnamicharts/wordpress diff --git a/examples/wordpress/swarm.yml b/examples/wordpress/swarm.yml index 550714d2a..889368d53 100644 --- a/examples/wordpress/swarm.yml +++ b/examples/wordpress/swarm.yml @@ -34,7 +34,7 @@ services: - MYSQL_ROOT_PASSWORD=db-root-pwd # replace with a stronger password - MYSQL_DATABASE=wp - MYSQL_USER=user - - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match WORDPRESS_DB_PASSWORD) + - MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match WORDPRESS_DB_PASSWORD) deploy: placement: constraints: diff --git a/examples/wordpress/tests.json b/examples/wordpress/tests.json index fa465449f..5f87a4b3e 100644 --- a/examples/wordpress/tests.json +++ b/examples/wordpress/tests.json @@ -1,7 +1,7 @@ { "name": "wordpress", "kinds": ["docker", "autoconf", "swarm", "kubernetes", "linux"], - "timeout": 60, + "timeout": 120, "delay": 120, "no_copy_container": true, "tests": [ diff --git a/examples/wordpress/wordpress-chart-values.yml b/examples/wordpress/wordpress-chart-values.yml index 259236d8c..a7bff53ff 100644 --- a/examples/wordpress/wordpress-chart-values.yml +++ b/examples/wordpress/wordpress-chart-values.yml @@ -8,4 +8,4 @@ wordpressTablePrefix: "changeme_" wordpressScheme: "https" mariadb: auth: - password: "changeme1337" \ No newline at end of file + password: "changeme1337" diff --git a/misc/integrations/autoconf.mariadb.ui.yml b/misc/integrations/autoconf.mariadb.ui.yml index 2da422312..a7498f64b 100644 --- a/misc/integrations/autoconf.mariadb.ui.yml +++ b/misc/integrations/autoconf.mariadb.ui.yml @@ -2,7 +2,7 @@ version: "3.5" services: bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -19,7 +19,7 @@ services: - bw-services bw-autoconf: - image: bunkerity/bunkerweb-autoconf:1.5.0 + image: bunkerity/bunkerweb-autoconf:1.5.1 depends_on: - bunkerweb - bw-docker @@ -32,7 +32,7 @@ services: - bw-docker bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - bunkerweb - bw-docker @@ -45,11 +45,12 @@ services: - bw-docker bw-docker: - image: tecnativa/docker-socket-proxy + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker @@ -66,7 +67,7 @@ services: - bw-docker bw-ui: - image: bunkerity/bunkerweb-ui:1.5.0 + image: bunkerity/bunkerweb-ui:1.5.1 networks: bw-docker: bw-universe: @@ -78,14 +79,12 @@ services: - AUTOCONF_MODE=yes - ADMIN_USERNAME=admin - ADMIN_PASSWORD=changeme - - ABSOLUTE_URI=http://www.example.com/changeme/ labels: - "bunkerweb.SERVER_NAME=www.example.com" - "bunkerweb.USE_UI=yes" - "bunkerweb.USE_REVERSE_PROXY=yes" - - "bunkerweb.REVERSE_PROXY_URL=/changeme/" + - "bunkerweb.REVERSE_PROXY_URL=/changeme" - "bunkerweb.REVERSE_PROXY_HOST=http://bw-ui:7000" - - "bunkerweb.REVERSE_PROXY_HEADERS=X-Script-Name /changeme" - "bunkerweb.INTERCEPTED_ERROR_CODES=400 404 405 413 429 500 501 502 503 504" volumes: diff --git a/misc/integrations/autoconf.mariadb.yml b/misc/integrations/autoconf.mariadb.yml index c85e08fda..235c4cdb7 100644 --- a/misc/integrations/autoconf.mariadb.yml +++ b/misc/integrations/autoconf.mariadb.yml @@ -2,7 +2,7 @@ version: "3.5" services: bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -19,7 +19,7 @@ services: - bw-services bw-autoconf: - image: bunkerity/bunkerweb-autoconf:1.5.0 + image: bunkerity/bunkerweb-autoconf:1.5.1 depends_on: - bunkerweb - bw-docker @@ -32,7 +32,7 @@ services: - bw-docker bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - bunkerweb - bw-docker @@ -45,11 +45,12 @@ services: - bw-docker bw-docker: - image: tecnativa/docker-socket-proxy + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/misc/integrations/autoconf.mysql.ui.yml b/misc/integrations/autoconf.mysql.ui.yml index dac0e0e5c..30d436093 100644 --- a/misc/integrations/autoconf.mysql.ui.yml +++ b/misc/integrations/autoconf.mysql.ui.yml @@ -2,7 +2,7 @@ version: "3.5" services: bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -19,7 +19,7 @@ services: - bw-services bw-autoconf: - image: bunkerity/bunkerweb-autoconf:1.5.0 + image: bunkerity/bunkerweb-autoconf:1.5.1 depends_on: - bunkerweb - bw-docker @@ -32,7 +32,7 @@ services: - bw-docker bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - bunkerweb - bw-docker @@ -45,11 +45,12 @@ services: - bw-docker bw-docker: - image: tecnativa/docker-socket-proxy + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker @@ -66,7 +67,7 @@ services: - bw-docker bw-ui: - image: bunkerity/bunkerweb-ui:1.5.0 + image: bunkerity/bunkerweb-ui:1.5.1 networks: bw-docker: bw-universe: @@ -78,14 +79,12 @@ services: - AUTOCONF_MODE=yes - ADMIN_USERNAME=changeme - ADMIN_PASSWORD=changeme - - ABSOLUTE_URI=http://www.example.com/changeme/ labels: - "bunkerweb.SERVER_NAME=www.example.com" - "bunkerweb.USE_UI=yes" - "bunkerweb.USE_REVERSE_PROXY=yes" - - "bunkerweb.REVERSE_PROXY_URL=/changeme/" + - "bunkerweb.REVERSE_PROXY_URL=/changeme" - "bunkerweb.REVERSE_PROXY_HOST=http://bw-ui:7000" - - "bunkerweb.REVERSE_PROXY_HEADERS=X-Script-Name /changeme" - "bunkerweb.INTERCEPTED_ERROR_CODES=400 404 405 413 429 500 501 502 503 504" volumes: diff --git a/misc/integrations/autoconf.mysql.yml b/misc/integrations/autoconf.mysql.yml index 3e66f69e3..cb5b47466 100644 --- a/misc/integrations/autoconf.mysql.yml +++ b/misc/integrations/autoconf.mysql.yml @@ -2,7 +2,7 @@ version: "3.5" services: bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -19,7 +19,7 @@ services: - bw-services bw-autoconf: - image: bunkerity/bunkerweb-autoconf:1.5.0 + image: bunkerity/bunkerweb-autoconf:1.5.1 depends_on: - bunkerweb - bw-docker @@ -32,7 +32,7 @@ services: - bw-docker bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - bunkerweb - bw-docker @@ -45,11 +45,12 @@ services: - bw-docker bw-docker: - image: tecnativa/docker-socket-proxy + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/misc/integrations/autoconf.postgres.ui.yml b/misc/integrations/autoconf.postgres.ui.yml index 9dbb960eb..c7dd061bb 100644 --- a/misc/integrations/autoconf.postgres.ui.yml +++ b/misc/integrations/autoconf.postgres.ui.yml @@ -2,7 +2,7 @@ version: "3.5" services: bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -19,7 +19,7 @@ services: - bw-services bw-autoconf: - image: bunkerity/bunkerweb-autoconf:1.5.0 + image: bunkerity/bunkerweb-autoconf:1.5.1 depends_on: - bunkerweb - bw-docker @@ -32,7 +32,7 @@ services: - bw-docker bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - bunkerweb - bw-docker @@ -45,11 +45,12 @@ services: - bw-docker bw-docker: - image: tecnativa/docker-socket-proxy + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker @@ -65,7 +66,7 @@ services: - bw-docker bw-ui: - image: bunkerity/bunkerweb-ui:1.5.0 + image: bunkerity/bunkerweb-ui:1.5.1 networks: bw-docker: bw-universe: @@ -77,14 +78,12 @@ services: - AUTOCONF_MODE=yes - ADMIN_USERNAME=admin - ADMIN_PASSWORD=changeme - - ABSOLUTE_URI=http://www.example.com/changeme/ labels: - "bunkerweb.SERVER_NAME=www.example.com" - "bunkerweb.USE_UI=yes" - "bunkerweb.USE_REVERSE_PROXY=yes" - - "bunkerweb.REVERSE_PROXY_URL=/changeme/" + - "bunkerweb.REVERSE_PROXY_URL=/changeme" - "bunkerweb.REVERSE_PROXY_HOST=http://bw-ui:7000" - - "bunkerweb.REVERSE_PROXY_HEADERS=X-Script-Name /changeme" - "bunkerweb.INTERCEPTED_ERROR_CODES=400 404 405 413 429 500 501 502 503 504" volumes: diff --git a/misc/integrations/autoconf.postgres.yml b/misc/integrations/autoconf.postgres.yml index 6924217b4..b88501afe 100644 --- a/misc/integrations/autoconf.postgres.yml +++ b/misc/integrations/autoconf.postgres.yml @@ -2,7 +2,7 @@ version: "3.5" services: bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -19,7 +19,7 @@ services: - bw-services bw-autoconf: - image: bunkerity/bunkerweb-autoconf:1.5.0 + image: bunkerity/bunkerweb-autoconf:1.5.1 depends_on: - bunkerweb - bw-docker @@ -32,7 +32,7 @@ services: - bw-docker bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - bunkerweb - bw-docker @@ -45,11 +45,12 @@ services: - bw-docker bw-docker: - image: tecnativa/docker-socket-proxy + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/misc/integrations/autoconf.ui.yml b/misc/integrations/autoconf.ui.yml index 478debadc..9e11fb74c 100644 --- a/misc/integrations/autoconf.ui.yml +++ b/misc/integrations/autoconf.ui.yml @@ -2,7 +2,7 @@ version: "3.5" services: bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -18,7 +18,7 @@ services: - bw-services bw-autoconf: - image: bunkerity/bunkerweb-autoconf:1.5.0 + image: bunkerity/bunkerweb-autoconf:1.5.1 depends_on: - bunkerweb - bw-docker @@ -32,7 +32,7 @@ services: - bw-docker bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - bunkerweb - bw-docker @@ -46,16 +46,17 @@ services: - bw-docker bw-docker: - image: tecnativa/docker-socket-proxy + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker bw-ui: - image: bunkerity/bunkerweb-ui:1.5.0 + image: bunkerity/bunkerweb-ui:1.5.1 networks: bw-docker: bw-universe: @@ -68,14 +69,12 @@ services: - AUTOCONF_MODE=yes - ADMIN_USERNAME=admin - ADMIN_PASSWORD=changeme - - ABSOLUTE_URI=http://www.example.com/changeme/ labels: - "bunkerweb.SERVER_NAME=www.example.com" - "bunkerweb.USE_UI=yes" - "bunkerweb.USE_REVERSE_PROXY=yes" - - "bunkerweb.REVERSE_PROXY_URL=/changeme/" + - "bunkerweb.REVERSE_PROXY_URL=/changeme" - "bunkerweb.REVERSE_PROXY_HOST=http://bw-ui:7000" - - "bunkerweb.REVERSE_PROXY_HEADERS=X-Script-Name /changeme" - "bunkerweb.INTERCEPTED_ERROR_CODES=400 404 405 413 429 500 501 502 503 504" volumes: diff --git a/misc/integrations/autoconf.yml b/misc/integrations/autoconf.yml index 46cd8ac75..ab55f503c 100644 --- a/misc/integrations/autoconf.yml +++ b/misc/integrations/autoconf.yml @@ -2,7 +2,7 @@ version: "3.5" services: bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -18,7 +18,7 @@ services: - bw-services bw-autoconf: - image: bunkerity/bunkerweb-autoconf:1.5.0 + image: bunkerity/bunkerweb-autoconf:1.5.1 depends_on: - bunkerweb - bw-docker @@ -32,7 +32,7 @@ services: - bw-docker bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - bunkerweb - bw-docker @@ -46,11 +46,12 @@ services: - bw-docker bw-docker: - image: tecnativa/docker-socket-proxy + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/misc/integrations/docker.mariadb.ui.yml b/misc/integrations/docker.mariadb.ui.yml index 1dd4669f5..68449646a 100644 --- a/misc/integrations/docker.mariadb.ui.yml +++ b/misc/integrations/docker.mariadb.ui.yml @@ -2,7 +2,7 @@ version: "3.5" services: bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -18,16 +18,15 @@ services: - USE_GZIP=yes - www.example.com_USE_UI=yes - www.example.com_USE_REVERSE_PROXY=yes - - www.example.com_REVERSE_PROXY_URL=/changeme/ + - www.example.com_REVERSE_PROXY_URL=/changeme - www.example.com_REVERSE_PROXY_HOST=http://bw-ui:7000 - - www.example.com_REVERSE_PROXY_HEADERS=X-Script-Name /changeme - www.example.com_INTERCEPTED_ERROR_CODES=400 404 405 413 429 500 501 502 503 504 networks: - bw-universe - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - bunkerweb - bw-docker @@ -39,16 +38,17 @@ services: - bw-docker bw-docker: - image: tecnativa/docker-socket-proxy + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker bw-ui: - image: bunkerity/bunkerweb-ui:1.5.0 + image: bunkerity/bunkerweb-ui:1.5.1 depends_on: - bw-docker environment: @@ -56,7 +56,6 @@ services: - DOCKER_HOST=tcp://bw-docker:2375 - ADMIN_USERNAME=changeme - ADMIN_PASSWORD=changeme # Remember to set a stronger password for the changeme user - - ABSOLUTE_URI=http://www.example.com/changeme/ networks: - bw-universe - bw-docker diff --git a/misc/integrations/docker.mariadb.yml b/misc/integrations/docker.mariadb.yml index f7a5a2a64..d60132f81 100644 --- a/misc/integrations/docker.mariadb.yml +++ b/misc/integrations/docker.mariadb.yml @@ -2,7 +2,7 @@ version: "3.5" services: bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -17,7 +17,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - bunkerweb - bw-docker @@ -29,11 +29,12 @@ services: - bw-docker bw-docker: - image: tecnativa/docker-socket-proxy + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/misc/integrations/docker.mysql.ui.yml b/misc/integrations/docker.mysql.ui.yml index ffd2039db..584c6c063 100644 --- a/misc/integrations/docker.mysql.ui.yml +++ b/misc/integrations/docker.mysql.ui.yml @@ -2,7 +2,7 @@ version: "3.5" services: bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -18,16 +18,15 @@ services: - USE_GZIP=yes - www.example.com_USE_UI=yes - www.example.com_USE_REVERSE_PROXY=yes - - www.example.com_REVERSE_PROXY_URL=/admin/ + - www.example.com_REVERSE_PROXY_URL=/changeme - www.example.com_REVERSE_PROXY_HOST=http://bw-ui:7000 - - www.example.com_REVERSE_PROXY_HEADERS=X-Script-Name /admin - www.example.com_INTERCEPTED_ERROR_CODES=400 404 405 413 429 500 501 502 503 504 networks: - bw-universe - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - bunkerweb - bw-docker @@ -39,16 +38,17 @@ services: - bw-docker bw-docker: - image: tecnativa/docker-socket-proxy + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker bw-ui: - image: bunkerity/bunkerweb-ui:1.5.0 + image: bunkerity/bunkerweb-ui:1.5.1 depends_on: - bw-docker environment: @@ -56,7 +56,6 @@ services: - DOCKER_HOST=tcp://bw-docker:2375 - ADMIN_USERNAME=admin - ADMIN_PASSWORD=changeme # Remember to set a stronger password for the admin user - - ABSOLUTE_URI=http://www.example.com/changeme/ networks: - bw-universe - bw-docker diff --git a/misc/integrations/docker.mysql.yml b/misc/integrations/docker.mysql.yml index 83e882c4b..7fdd23052 100644 --- a/misc/integrations/docker.mysql.yml +++ b/misc/integrations/docker.mysql.yml @@ -2,7 +2,7 @@ version: "3.5" services: bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -17,7 +17,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - bunkerweb - bw-docker @@ -29,11 +29,12 @@ services: - bw-docker bw-docker: - image: tecnativa/docker-socket-proxy + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/misc/integrations/docker.postgres.ui.yml b/misc/integrations/docker.postgres.ui.yml index 07f3c1618..79a20e4ba 100644 --- a/misc/integrations/docker.postgres.ui.yml +++ b/misc/integrations/docker.postgres.ui.yml @@ -2,7 +2,7 @@ version: "3.5" services: bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -19,16 +19,15 @@ services: - www.example.com_USE_UI=yes - www.example.com_SERVE_FILES=no - www.example.com_USE_REVERSE_PROXY=yes - - www.example.com_REVERSE_PROXY_URL=/admin/ + - www.example.com_REVERSE_PROXY_URL=/changeme - www.example.com_REVERSE_PROXY_HOST=http://bw-ui:7000 - - www.example.com_REVERSE_PROXY_HEADERS=X-Script-Name /admin - www.example.com_INTERCEPTED_ERROR_CODES=400 404 405 413 429 500 501 502 503 504 networks: - bw-universe - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - bunkerweb - bw-docker @@ -40,16 +39,17 @@ services: - bw-docker bw-docker: - image: tecnativa/docker-socket-proxy + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker bw-ui: - image: bunkerity/bunkerweb-ui:1.5.0 + image: bunkerity/bunkerweb-ui:1.5.1 depends_on: - bw-docker environment: @@ -57,7 +57,6 @@ services: - DOCKER_HOST=tcp://bw-docker:2375 - ADMIN_USERNAME=admin - ADMIN_PASSWORD=changeme # Remember to set a stronger password for the admin user - - ABSOLUTE_URI=http://www.example.com/changeme networks: - bw-universe - bw-docker diff --git a/misc/integrations/docker.postgres.yml b/misc/integrations/docker.postgres.yml index 069a76523..672fa8798 100644 --- a/misc/integrations/docker.postgres.yml +++ b/misc/integrations/docker.postgres.yml @@ -2,7 +2,7 @@ version: "3.5" services: bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -17,7 +17,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - bunkerweb - bw-docker @@ -29,11 +29,12 @@ services: - bw-docker bw-docker: - image: tecnativa/docker-socket-proxy + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/misc/integrations/docker.ui.yml b/misc/integrations/docker.ui.yml index dfa8993af..16b11144e 100644 --- a/misc/integrations/docker.ui.yml +++ b/misc/integrations/docker.ui.yml @@ -2,7 +2,7 @@ version: "3.5" services: bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -14,16 +14,15 @@ services: - API_WHITELIST_IP=127.0.0.0/8 10.20.30.0/24 - www.example.com_USE_UI=yes - www.example.com_USE_REVERSE_PROXY=yes - - www.example.com_REVERSE_PROXY_URL=/changeme/ + - www.example.com_REVERSE_PROXY_URL=/changeme - www.example.com_REVERSE_PROXY_HOST=http://bw-ui:7000 - - www.example.com_REVERSE_PROXY_HEADERS=X-Script-Name /changeme - www.example.com_INTERCEPTED_ERROR_CODES=400 404 405 413 429 500 501 502 503 504 networks: - bw-universe - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - bunkerweb - bw-docker @@ -36,16 +35,17 @@ services: - bw-docker bw-docker: - image: tecnativa/docker-socket-proxy + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker bw-ui: - image: bunkerity/bunkerweb-ui:1.5.0 + image: bunkerity/bunkerweb-ui:1.5.1 depends_on: - bw-docker volumes: @@ -54,7 +54,6 @@ services: - DOCKER_HOST=tcp://bw-docker:2375 - ADMIN_USERNAME=changeme - ADMIN_PASSWORD=changeme - - ABSOLUTE_URI=http://www.example.com/changeme/ networks: - bw-universe - bw-docker diff --git a/misc/integrations/docker.yml b/misc/integrations/docker.yml index 7da82339e..0a416bcbf 100644 --- a/misc/integrations/docker.yml +++ b/misc/integrations/docker.yml @@ -2,7 +2,7 @@ version: "3.5" services: bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - 80:8080 - 443:8443 @@ -16,7 +16,7 @@ services: - bw-services bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 depends_on: - bunkerweb - bw-docker @@ -29,11 +29,12 @@ services: - bw-docker bw-docker: - image: tecnativa/docker-socket-proxy + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - CONTAINERS=1 + - LOG_LEVEL=warning networks: - bw-docker diff --git a/misc/integrations/k8s.mariadb.ui.yml b/misc/integrations/k8s.mariadb.ui.yml index b66e23c96..1c5ea146a 100644 --- a/misc/integrations/k8s.mariadb.ui.yml +++ b/misc/integrations/k8s.mariadb.ui.yml @@ -48,7 +48,7 @@ spec: containers: # using bunkerweb as name is mandatory - name: bunkerweb - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 imagePullPolicy: Always securityContext: runAsUser: 101 @@ -118,7 +118,7 @@ spec: serviceAccountName: sa-bunkerweb containers: - name: bunkerweb-controller - image: bunkerity/bunkerweb-autoconf:1.5.0 + image: bunkerity/bunkerweb-autoconf:1.5.1 imagePullPolicy: Always env: - name: KUBERNETES_MODE @@ -145,7 +145,7 @@ spec: serviceAccountName: sa-bunkerweb containers: - name: bunkerweb-scheduler - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 imagePullPolicy: Always env: - name: KUBERNETES_MODE @@ -230,15 +230,13 @@ spec: serviceAccountName: sa-bunkerweb containers: - name: bunkerweb-ui - image: bunkerity/bunkerweb-ui:1.5.0 + image: bunkerity/bunkerweb-ui:1.5.1 imagePullPolicy: Always env: - name: ADMIN_USERNAME value: "changeme" - name: "ADMIN_PASSWORD" value: "changeme" - - name: "ABSOLUTE_URI" - value: "http://www.example.com/changeme/" - name: KUBERNETES_MODE value: "YES" - name: "DATABASE_URI" @@ -313,14 +311,13 @@ metadata: name: ingress annotations: bunkerweb.io/www.example.com_USE_UI: "yes" - bunkerweb.io/www.example.com_REVERSE_PROXY_HEADERS_1: "X-Script-Name /changeme" bunkerweb.io/www.example.com_INTERCEPTED_ERROR_CODES: "400 404 405 413 429 500 501 502 503 504" spec: rules: - host: www.example.com http: paths: - - path: /changeme/ + - path: /changeme pathType: Prefix backend: service: diff --git a/misc/integrations/k8s.mariadb.yml b/misc/integrations/k8s.mariadb.yml index 075ab500b..69b826df2 100644 --- a/misc/integrations/k8s.mariadb.yml +++ b/misc/integrations/k8s.mariadb.yml @@ -48,7 +48,7 @@ spec: containers: # using bunkerweb as name is mandatory - name: bunkerweb - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 imagePullPolicy: Always securityContext: runAsUser: 101 @@ -118,7 +118,7 @@ spec: serviceAccountName: sa-bunkerweb containers: - name: bunkerweb-controller - image: bunkerity/bunkerweb-autoconf:1.5.0 + image: bunkerity/bunkerweb-autoconf:1.5.1 imagePullPolicy: Always env: - name: KUBERNETES_MODE @@ -145,7 +145,7 @@ spec: serviceAccountName: sa-bunkerweb containers: - name: bunkerweb-scheduler - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 imagePullPolicy: Always env: - name: KUBERNETES_MODE diff --git a/misc/integrations/k8s.mysql.ui.yml b/misc/integrations/k8s.mysql.ui.yml index 518d87b49..f8119d22a 100644 --- a/misc/integrations/k8s.mysql.ui.yml +++ b/misc/integrations/k8s.mysql.ui.yml @@ -48,7 +48,7 @@ spec: containers: # using bunkerweb as name is mandatory - name: bunkerweb - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 imagePullPolicy: Always securityContext: runAsUser: 101 @@ -118,7 +118,7 @@ spec: serviceAccountName: sa-bunkerweb containers: - name: bunkerweb-controller - image: bunkerity/bunkerweb-autoconf:1.5.0 + image: bunkerity/bunkerweb-autoconf:1.5.1 imagePullPolicy: Always env: - name: KUBERNETES_MODE @@ -145,7 +145,7 @@ spec: serviceAccountName: sa-bunkerweb containers: - name: bunkerweb-scheduler - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 imagePullPolicy: Always env: - name: KUBERNETES_MODE @@ -230,15 +230,13 @@ spec: serviceAccountName: sa-bunkerweb containers: - name: bunkerweb-ui - image: bunkerity/bunkerweb-ui:1.5.0 + image: bunkerity/bunkerweb-ui:1.5.1 imagePullPolicy: Always env: - name: ADMIN_USERNAME value: "changeme" - name: "ADMIN_PASSWORD" value: "changeme" - - name: "ABSOLUTE_URI" - value: "http://www.example.com/changeme/" - name: KUBERNETES_MODE value: "YES" - name: "DATABASE_URI" @@ -312,14 +310,13 @@ metadata: name: ingress annotations: bunkerweb.io/www.example.com_USE_UI: "yes" - bunkerweb.io/www.example.com_REVERSE_PROXY_HEADERS_1: "X-Script-Name /changeme" bunkerweb.io/www.example.com_INTERCEPTED_ERROR_CODES: "400 404 405 413 429 500 501 502 503 504" spec: rules: - host: www.example.com http: paths: - - path: /changeme/ + - path: /changeme pathType: Prefix backend: service: diff --git a/misc/integrations/k8s.mysql.yml b/misc/integrations/k8s.mysql.yml index 9d77a08b1..59f0cc95f 100644 --- a/misc/integrations/k8s.mysql.yml +++ b/misc/integrations/k8s.mysql.yml @@ -48,7 +48,7 @@ spec: containers: # using bunkerweb as name is mandatory - name: bunkerweb - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 imagePullPolicy: Always securityContext: runAsUser: 101 @@ -118,7 +118,7 @@ spec: serviceAccountName: sa-bunkerweb containers: - name: bunkerweb-controller - image: bunkerity/bunkerweb-autoconf:1.5.0 + image: bunkerity/bunkerweb-autoconf:1.5.1 imagePullPolicy: Always env: - name: KUBERNETES_MODE @@ -144,7 +144,7 @@ spec: spec: containers: - name: bunkerweb-controller - image: bunkerity/bunkerweb-autoconf:1.5.0 + image: bunkerity/bunkerweb-autoconf:1.5.1 imagePullPolicy: Always env: - name: KUBERNETES_MODE diff --git a/misc/integrations/k8s.postgres.ui.yml b/misc/integrations/k8s.postgres.ui.yml index 135d7e239..d3c73b71e 100644 --- a/misc/integrations/k8s.postgres.ui.yml +++ b/misc/integrations/k8s.postgres.ui.yml @@ -48,7 +48,7 @@ spec: containers: # using bunkerweb as name is mandatory - name: bunkerweb - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 imagePullPolicy: Always securityContext: runAsUser: 101 @@ -118,7 +118,7 @@ spec: serviceAccountName: sa-bunkerweb containers: - name: bunkerweb-controller - image: bunkerity/bunkerweb-autoconf:1.5.0 + image: bunkerity/bunkerweb-autoconf:1.5.1 imagePullPolicy: Always env: - name: KUBERNETES_MODE @@ -145,7 +145,7 @@ spec: serviceAccountName: sa-bunkerweb containers: - name: bunkerweb-scheduler - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 imagePullPolicy: Always env: - name: KUBERNETES_MODE @@ -230,15 +230,13 @@ spec: serviceAccountName: sa-bunkerweb containers: - name: bunkerweb-ui - image: bunkerity/bunkerweb-ui:1.5.0 + image: bunkerity/bunkerweb-ui:1.5.1 imagePullPolicy: Always env: - name: ADMIN_USERNAME value: "changeme" - name: "ADMIN_PASSWORD" value: "changeme" - - name: "ABSOLUTE_URI" - value: "http://www.example.com/changeme/" - name: KUBERNETES_MODE value: "YES" - name: "DATABASE_URI" @@ -312,14 +310,13 @@ metadata: name: ingress annotations: bunkerweb.io/www.example.com_USE_UI: "yes" - bunkerweb.io/www.example.com_REVERSE_PROXY_HEADERS_1: "X-Script-Name /changeme" bunkerweb.io/www.example.com_INTERCEPTED_ERROR_CODES: "400 404 405 413 429 500 501 502 503 504" spec: rules: - host: www.example.com http: paths: - - path: /changeme/ + - path: /changeme pathType: Prefix backend: service: diff --git a/misc/integrations/k8s.postgres.yml b/misc/integrations/k8s.postgres.yml index ca75e2ea7..071b0893f 100644 --- a/misc/integrations/k8s.postgres.yml +++ b/misc/integrations/k8s.postgres.yml @@ -48,7 +48,7 @@ spec: containers: # using bunkerweb as name is mandatory - name: bunkerweb - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 imagePullPolicy: Always securityContext: runAsUser: 101 @@ -118,7 +118,7 @@ spec: serviceAccountName: sa-bunkerweb containers: - name: bunkerweb-controller - image: bunkerity/bunkerweb-autoconf:1.5.0 + image: bunkerity/bunkerweb-autoconf:1.5.1 imagePullPolicy: Always env: - name: KUBERNETES_MODE @@ -144,7 +144,7 @@ spec: spec: containers: - name: bunkerweb-controller - image: bunkerity/bunkerweb-autoconf:1.5.0 + image: bunkerity/bunkerweb-autoconf:1.5.1 imagePullPolicy: Always env: - name: KUBERNETES_MODE diff --git a/misc/integrations/swarm.mariadb.ui.yml b/misc/integrations/swarm.mariadb.ui.yml index 57c48666b..ca8668487 100644 --- a/misc/integrations/swarm.mariadb.ui.yml +++ b/misc/integrations/swarm.mariadb.ui.yml @@ -2,7 +2,7 @@ version: "3.5" services: bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - published: 80 target: 8080 @@ -32,7 +32,7 @@ services: - "bunkerweb.INSTANCE" bw-autoconf: - image: bunkerity/bunkerweb-autoconf:1.5.0 + image: bunkerity/bunkerweb-autoconf:1.5.1 environment: - SWARM_MODE=yes - DOCKER_HOST=tcp://bw-docker:2375 @@ -42,7 +42,7 @@ services: - bw-docker bw-docker: - image: tecnativa/docker-socket-proxy + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: @@ -51,6 +51,7 @@ services: - SERVICES=1 - SWARM=1 - TASKS=1 + - LOG_LEVEL=warning networks: - bw-docker deploy: @@ -59,7 +60,7 @@ services: - "node.role == manager" bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 environment: - SWARM_MODE=yes - DOCKER_HOST=tcp://bw-docker:2375 @@ -86,13 +87,12 @@ services: - bw-universe bw-ui: - image: bunkerity/bunkerweb-ui:1.5.0 + image: bunkerity/bunkerweb-ui:1.5.1 environment: - DATABASE_URI=mariadb+pymysql://bunkerweb:changeme@bw-db:3306/db # Remember to set a stronger password for the database - DOCKER_HOST=tcp://bw-docker:2375 - ADMIN_USERNAME=changeme - ADMIN_PASSWORD=changeme # Remember to set a stronger password for the changeme user - - ABSOLUTE_URI=http://www.example.com/changeme/ networks: - bw-universe - bw-docker @@ -101,9 +101,8 @@ services: - "bunkerweb.SERVER_NAME=www.example.com" - "bunkerweb.USE_UI=yes" - "bunkerweb.USE_REVERSE_PROXY=yes" - - "bunkerweb.REVERSE_PROXY_URL=/changeme/" + - "bunkerweb.REVERSE_PROXY_URL=/changeme" - "bunkerweb.REVERSE_PROXY_HOST=http://bw-ui:7000" - - "bunkerweb.REVERSE_PROXY_HEADERS=X-Script-Name /changeme" - "bunkerweb.INTERCEPTED_ERROR_CODES=400 404 405 413 429 500 501 502 503 504" volumes: diff --git a/misc/integrations/swarm.mariadb.yml b/misc/integrations/swarm.mariadb.yml index e95af2ef6..a7270c06e 100644 --- a/misc/integrations/swarm.mariadb.yml +++ b/misc/integrations/swarm.mariadb.yml @@ -2,7 +2,7 @@ version: "3.5" services: bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - published: 80 target: 8080 @@ -32,7 +32,7 @@ services: - "bunkerweb.INSTANCE" bw-autoconf: - image: bunkerity/bunkerweb-autoconf:1.5.0 + image: bunkerity/bunkerweb-autoconf:1.5.1 environment: - SWARM_MODE=yes - DOCKER_HOST=tcp://bw-docker:2375 @@ -46,7 +46,7 @@ services: - "node.role == worker" bw-docker: - image: tecnativa/docker-socket-proxy + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: @@ -55,6 +55,7 @@ services: - SERVICES=1 - SWARM=1 - TASKS=1 + - LOG_LEVEL=warning networks: - bw-docker deploy: @@ -63,7 +64,7 @@ services: - "node.role == manager" bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 environment: - SWARM_MODE=yes - DOCKER_HOST=tcp://bw-docker:2375 diff --git a/misc/integrations/swarm.mysql.ui.yml b/misc/integrations/swarm.mysql.ui.yml index b3401a304..e6f470c77 100644 --- a/misc/integrations/swarm.mysql.ui.yml +++ b/misc/integrations/swarm.mysql.ui.yml @@ -2,7 +2,7 @@ version: "3.5" services: bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - published: 80 target: 8080 @@ -32,7 +32,7 @@ services: - "bunkerweb.INSTANCE" bw-autoconf: - image: bunkerity/bunkerweb-autoconf:1.5.0 + image: bunkerity/bunkerweb-autoconf:1.5.1 environment: - SWARM_MODE=yes - DOCKER_HOST=tcp://bw-docker:2375 @@ -42,7 +42,7 @@ services: - bw-docker bw-docker: - image: tecnativa/docker-socket-proxy + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: @@ -51,6 +51,7 @@ services: - SERVICES=1 - SWARM=1 - TASKS=1 + - LOG_LEVEL=warning networks: - bw-docker deploy: @@ -59,7 +60,7 @@ services: - "node.role == manager" bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 environment: - SWARM_MODE=yes - DOCKER_HOST=tcp://bw-docker:2375 @@ -86,13 +87,12 @@ services: - bw-universe bw-ui: - image: bunkerity/bunkerweb-ui:1.5.0 + image: bunkerity/bunkerweb-ui:1.5.1 environment: - DATABASE_URI=mariadb+pymysql://bunkerweb:changeme@bw-db:3306/db # Remember to set a stronger password for the database - DOCKER_HOST=tcp://bw-docker:2375 - ADMIN_USERNAME=changeme - ADMIN_PASSWORD=changeme # Remember to set a stronger password for the changeme user - - ABSOLUTE_URI=http://www.example.com/changeme/ networks: - bw-universe - bw-docker @@ -101,9 +101,8 @@ services: - "bunkerweb.SERVER_NAME=www.example.com" - "bunkerweb.USE_UI=yes" - "bunkerweb.USE_REVERSE_PROXY=yes" - - "bunkerweb.REVERSE_PROXY_URL=/changeme/" + - "bunkerweb.REVERSE_PROXY_URL=/changeme" - "bunkerweb.REVERSE_PROXY_HOST=http://bw-ui:7000" - - "bunkerweb.REVERSE_PROXY_HEADERS=X-Script-Name /changeme" - "bunkerweb.INTERCEPTED_ERROR_CODES=400 404 405 413 429 500 501 502 503 504" volumes: diff --git a/misc/integrations/swarm.mysql.yml b/misc/integrations/swarm.mysql.yml index e46142a7c..302323e0e 100644 --- a/misc/integrations/swarm.mysql.yml +++ b/misc/integrations/swarm.mysql.yml @@ -2,7 +2,7 @@ version: "3.5" services: bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - published: 80 target: 8080 @@ -32,7 +32,7 @@ services: - "bunkerweb.INSTANCE" bw-autoconf: - image: bunkerity/bunkerweb-autoconf:1.5.0 + image: bunkerity/bunkerweb-autoconf:1.5.1 environment: - SWARM_MODE=yes - DOCKER_HOST=tcp://bw-docker:2375 @@ -42,7 +42,7 @@ services: - bw-docker bw-docker: - image: tecnativa/docker-socket-proxy + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: @@ -51,6 +51,7 @@ services: - SERVICES=1 - SWARM=1 - TASKS=1 + - LOG_LEVEL=warning networks: - bw-docker deploy: @@ -59,7 +60,7 @@ services: - "node.role == manager" bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 environment: - SWARM_MODE=yes - DOCKER_HOST=tcp://bw-docker:2375 diff --git a/misc/integrations/swarm.postgres.ui.yml b/misc/integrations/swarm.postgres.ui.yml index 9f9513809..e3cc2a070 100644 --- a/misc/integrations/swarm.postgres.ui.yml +++ b/misc/integrations/swarm.postgres.ui.yml @@ -1,8 +1,8 @@ -version: "3.5" + version: "3.5" services: bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - published: 80 target: 8080 @@ -32,7 +32,7 @@ services: - "bunkerweb.INSTANCE" bw-autoconf: - image: bunkerity/bunkerweb-autoconf:1.5.0 + image: bunkerity/bunkerweb-autoconf:1.5.1 environment: - SWARM_MODE=yes - DOCKER_HOST=tcp://bw-docker:2375 @@ -42,7 +42,7 @@ services: - bw-docker bw-docker: - image: tecnativa/docker-socket-proxy + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: @@ -51,6 +51,7 @@ services: - SERVICES=1 - SWARM=1 - TASKS=1 + - LOG_LEVEL=warning networks: - bw-docker deploy: @@ -59,7 +60,7 @@ services: - "node.role == manager" bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 environment: - SWARM_MODE=yes - DOCKER_HOST=tcp://bw-docker:2375 @@ -85,13 +86,12 @@ services: - bw-universe bw-ui: - image: bunkerity/bunkerweb-ui:1.5.0 + image: bunkerity/bunkerweb-ui:1.5.1 environment: - DATABASE_URI=postgresql://bunkerweb:changeme@bw-db:5432/db - DOCKER_HOST=tcp://bw-docker:2375 - ADMIN_USERNAME=changeme - ADMIN_PASSWORD=changeme - - ABSOLUTE_URI=http://www.example.com/changeme/ networks: - bw-universe - bw-docker @@ -100,9 +100,8 @@ services: - "bunkerweb.SERVER_NAME=www.example.com" - "bunkerweb.USE_UI=yes" - "bunkerweb.USE_REVERSE_PROXY=yes" - - "bunkerweb.REVERSE_PROXY_URL=/changeme/" + - "bunkerweb.REVERSE_PROXY_URL=/changeme" - "bunkerweb.REVERSE_PROXY_HOST=http://bw-ui:7000" - - "bunkerweb.REVERSE_PROXY_HEADERS=X-Script-Name /changeme" - "bunkerweb.INTERCEPTED_ERROR_CODES=400 404 405 413 429 500 501 502 503 504" volumes: diff --git a/misc/integrations/swarm.postgres.yml b/misc/integrations/swarm.postgres.yml index 908308bc7..bcc57609d 100644 --- a/misc/integrations/swarm.postgres.yml +++ b/misc/integrations/swarm.postgres.yml @@ -2,7 +2,7 @@ version: "3.5" services: bunkerweb: - image: bunkerity/bunkerweb:1.5.0 + image: bunkerity/bunkerweb:1.5.1 ports: - published: 80 target: 8080 @@ -32,7 +32,7 @@ services: - "bunkerweb.INSTANCE" bw-autoconf: - image: bunkerity/bunkerweb-autoconf:1.5.0 + image: bunkerity/bunkerweb-autoconf:1.5.1 environment: - SWARM_MODE=yes - DOCKER_HOST=tcp://bw-docker:2375 @@ -42,7 +42,7 @@ services: - bw-docker bw-docker: - image: tecnativa/docker-socket-proxy + image: tecnativa/docker-socket-proxy:nightly volumes: - /var/run/docker.sock:/var/run/docker.sock:ro environment: @@ -51,6 +51,7 @@ services: - SERVICES=1 - SWARM=1 - TASKS=1 + - LOG_LEVEL=warning networks: - bw-docker deploy: @@ -59,7 +60,7 @@ services: - "node.role == manager" bw-scheduler: - image: bunkerity/bunkerweb-scheduler:1.5.0 + image: bunkerity/bunkerweb-scheduler:1.5.1 environment: - SWARM_MODE=yes - DOCKER_HOST=tcp://bw-docker:2375 diff --git a/misc/update-version.sh b/misc/update-version.sh index a5ffab00b..e227d865b 100755 --- a/misc/update-version.sh +++ b/misc/update-version.sh @@ -24,4 +24,8 @@ sed -i "s@${OLD_VERSION}@${NEW_VERSION}@g" README.md sed -i "s@${OLD_VERSION}@${NEW_VERSION}@g" tests/ui/docker-compose.yml for test in tests/core/* ; do sed -i "s@${OLD_VERSION}@${NEW_VERSION}@g" ${test}/docker-compose.yml -done \ No newline at end of file +done +# linux +sed -i "s@${OLD_VERSION}@${NEW_VERSION}@g" src/linux/scripts/*.sh +# db +sed -i "s@${OLD_VERSION}@${NEW_VERSION}@g" src/common/db/model.py diff --git a/mkdocs.yml b/mkdocs.yml index 534172471..cdd05b98b 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -68,4 +68,6 @@ extra: plugins: - search - - print-site \ No newline at end of file + - print-site + - mike: + canonical_version: latest \ No newline at end of file diff --git a/src/VERSION b/src/VERSION index 3e1ad720b..8e03717dc 100644 --- a/src/VERSION +++ b/src/VERSION @@ -1 +1 @@ -1.5.0 \ No newline at end of file +1.5.1 \ No newline at end of file diff --git a/src/autoconf/Config.py b/src/autoconf/Config.py index f0b6ff2b2..3726540d2 100644 --- a/src/autoconf/Config.py +++ b/src/autoconf/Config.py @@ -1,16 +1,17 @@ +#!/usr/bin/python3 + from os import getenv from time import sleep +from typing import Optional -from ConfigCaller import ConfigCaller -from Database import Database -from logger import setup_logger +from ConfigCaller import ConfigCaller # type: ignore +from Database import Database # type: ignore +from logger import setup_logger # type: ignore class Config(ConfigCaller): - def __init__(self, ctrl_type, lock=None): + def __init__(self): super().__init__() - self.__ctrl_type = ctrl_type - self.__lock = lock self.__logger = setup_logger("Config", getenv("LOG_LEVEL", "INFO")) self.__instances = [] self.__services = [] diff --git a/src/autoconf/Controller.py b/src/autoconf/Controller.py index 44c3208f7..26d901f41 100644 --- a/src/autoconf/Controller.py +++ b/src/autoconf/Controller.py @@ -1,14 +1,21 @@ +#!/usr/bin/python3 + from abc import ABC, abstractmethod from os import getenv from time import sleep +from typing import Literal, Optional, Union from Config import Config -from logger import setup_logger +from logger import setup_logger # type: ignore -class Controller(ABC): - def __init__(self, ctrl_type, lock=None): +class Controller(Config): + def __init__( + self, + ctrl_type: Union[Literal["docker"], Literal["swarm"], Literal["kubernetes"]], + ): + super().__init__() self._type = ctrl_type self._instances = [] self._services = [] @@ -24,15 +31,16 @@ class Controller(ABC): self._configs = { config_type: {} for config_type in self._supported_config_types } - self._config = Config(ctrl_type, lock) - self.__logger = setup_logger("Controller", getenv("LOG_LEVEL", "INFO")) + self._logger = setup_logger( + f"{self._type}-controller", getenv("LOG_LEVEL", "INFO") + ) - def wait(self, wait_time): + def wait(self, wait_time: int) -> list: all_ready = False while not all_ready: self._instances = self.get_instances() if not self._instances: - self.__logger.warning( + self._logger.warning( f"No instance found, waiting {wait_time}s ...", ) sleep(wait_time) @@ -40,7 +48,7 @@ class Controller(ABC): all_ready = True for instance in self._instances: if not instance["health"]: - self.__logger.warning( + self._logger.warning( f"Instance {instance['name']} is not ready, waiting {wait_time}s ...", ) sleep(wait_time) @@ -59,8 +67,7 @@ class Controller(ABC): def get_instances(self): instances = [] for controller_instance in self._get_controller_instances(): - for instance in self._to_instances(controller_instance): - instances.append(instance) + instances.extend(self._to_instances(controller_instance)) return instances @abstractmethod @@ -76,20 +83,18 @@ class Controller(ABC): pass def _set_autoconf_load_db(self): - if not self._config._db.is_autoconf_loaded(): - ret = self._config._db.set_autoconf_load(True) + if not self._db.is_autoconf_loaded(): + ret = self._db.set_autoconf_load(True) if ret: - self.__logger.warning( + self._logger.warning( f"Can't set autoconf loaded metadata to true in database: {ret}", ) def get_services(self): services = [] for controller_service in self._get_controller_services(): - for service in self._to_services(controller_service): - services.append(service) - for static_service in self._get_static_services(): - services.append(static_service) + services.extend(self._to_services(controller_service)) + services.extend(self._get_static_services()) return services @abstractmethod @@ -106,8 +111,8 @@ class Controller(ABC): def _is_service_present(self, server_name): for service in self._services: - if not "SERVER_NAME" in service or service["SERVER_NAME"] == "": + if not "SERVER_NAME" in service or not service["SERVER_NAME"]: continue - if server_name == service["SERVER_NAME"].split(" ")[0]: + if server_name == service["SERVER_NAME"].strip().split(" ")[0]: return True return False diff --git a/src/autoconf/DockerController.py b/src/autoconf/DockerController.py index 21a840b8c..994fdaa49 100644 --- a/src/autoconf/DockerController.py +++ b/src/autoconf/DockerController.py @@ -1,30 +1,29 @@ -from os import getenv +#!/usr/bin/python3 + +from typing import Any, Dict, List from docker import DockerClient from re import compile as re_compile from traceback import format_exc +from docker.models.containers import Container from Controller import Controller -from ConfigCaller import ConfigCaller -from logger import setup_logger -class DockerController(Controller, ConfigCaller): +class DockerController(Controller): def __init__(self, docker_host): - Controller.__init__(self, "docker") - ConfigCaller.__init__(self) + super().__init__("docker") self.__client = DockerClient(base_url=docker_host) - self.__logger = setup_logger("docker-controller", getenv("LOG_LEVEL", "INFO")) self.__custom_confs_rx = re_compile( r"^bunkerweb.CUSTOM_CONF_(SERVER_HTTP|MODSEC_CRS|MODSEC)_(.+)$" ) - def _get_controller_instances(self): + def _get_controller_instances(self) -> List[Container]: return self.__client.containers.list(filters={"label": "bunkerweb.INSTANCE"}) - def _get_controller_services(self): + def _get_controller_services(self) -> List[Container]: return self.__client.containers.list(filters={"label": "bunkerweb.SERVER_NAME"}) - def _to_instances(self, controller_instance): + def _to_instances(self, controller_instance) -> List[dict]: instance = {} instance["name"] = controller_instance.name instance["hostname"] = controller_instance.name @@ -40,18 +39,18 @@ class DockerController(Controller, ConfigCaller): instance["env"][variable] = value return [instance] - def _to_services(self, controller_service): + def _to_services(self, controller_service) -> List[dict]: service = {} for variable, value in controller_service.labels.items(): if not variable.startswith("bunkerweb."): continue real_variable = variable.replace("bunkerweb.", "", 1) - if not self._is_multisite_setting(real_variable): + if not self._is_setting_context(real_variable, "multisite"): continue service[real_variable] = value return [service] - def _get_static_services(self): + def _get_static_services(self) -> List[dict]: services = [] variables = {} for instance in self.__client.containers.list( @@ -71,14 +70,14 @@ class DockerController(Controller, ConfigCaller): for variable, value in variables.items(): prefix = variable.split("_")[0] real_variable = variable.replace(f"{prefix}_", "", 1) - if prefix == server_name and self._is_multisite_setting( - real_variable + if prefix == server_name and self._is_setting_context( + real_variable, "multisite" ): service[real_variable] = value services.append(service) return services - def get_configs(self): + def get_configs(self) -> Dict[str, Dict[str, Any]]: configs = {config_type: {} for config_type in self._supported_config_types} # get site configs from labels for container in self.__client.containers.list( @@ -106,10 +105,8 @@ class DockerController(Controller, ConfigCaller): ] = value return configs - def apply_config(self): - return self._config.apply( - self._instances, self._services, configs=self._configs - ) + def apply_config(self) -> bool: + return self.apply(self._instances, self._services, configs=self._configs) def process_events(self): self._set_autoconf_load_db() @@ -118,27 +115,22 @@ class DockerController(Controller, ConfigCaller): self._instances = self.get_instances() self._services = self.get_services() self._configs = self.get_configs() - if not self._config.update_needed( + if not self.update_needed( self._instances, self._services, configs=self._configs ): continue - self.__logger.info( + self._logger.info( "Caught Docker event, deploying new configuration ..." ) if not self.apply_config(): - self.__logger.error("Error while deploying new configuration") + self._logger.error("Error while deploying new configuration") else: - self.__logger.info( + self._logger.info( "Successfully deployed new configuration 🚀", ) - if not self._config._db.is_autoconf_loaded(): - ret = self._config._db.set_autoconf_load(True) - if ret: - self.__logger.warning( - f"Can't set autoconf loaded metadata to true in database: {ret}", - ) + self._set_autoconf_load_db() except: - self.__logger.error( + self._logger.error( f"Exception while processing events :\n{format_exc()}" ) diff --git a/src/autoconf/Dockerfile b/src/autoconf/Dockerfile index 00ad53a4e..eff6f29aa 100644 --- a/src/autoconf/Dockerfile +++ b/src/autoconf/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.11.3-alpine AS builder +FROM python:3.11.4-alpine AS builder # Copy python requirements COPY src/common/gen/requirements.txt /tmp/req/requirements.txt @@ -14,12 +14,13 @@ RUN apk add --no-cache --virtual .build-deps g++ gcc musl-dev jpeg-dev zlib-dev # Install python requirements RUN export MAKEFLAGS="-j$(nproc)" && \ pip install --no-cache-dir --upgrade pip && \ - pip install --no-cache-dir --upgrade wheel && \ + pip install --no-cache-dir --upgrade pip-tools wheel setuptools && \ mkdir -p /usr/share/bunkerweb/deps/python && \ pip install --no-cache-dir --require-hashes --target /usr/share/bunkerweb/deps/python -r /usr/share/bunkerweb/deps/requirements.txt # Remove build dependencies -RUN apk del .build-deps +RUN apk del .build-deps && \ + rm -rf /var/cache/apk/* # Copy files # can't exclude specific files/dir from . so we are copying everything by hand @@ -32,7 +33,7 @@ COPY src/common/helpers /usr/share/bunkerweb/helpers COPY src/common/settings.json /usr/share/bunkerweb/settings.json COPY src/common/utils /usr/share/bunkerweb/utils -FROM python:3.11.3-alpine +FROM python:3.11.4-alpine # Set default umask to prevent huge recursive chmod increasing the final image size RUN umask 027 @@ -60,7 +61,7 @@ RUN apk add --no-cache bash && \ chmod 750 /usr/share/bunkerweb/cli/main.py /usr/share/bunkerweb/helpers/*.sh /usr/bin/bwcli /usr/share/bunkerweb/autoconf/main.py /usr/share/bunkerweb/deps/python/bin/* # Fix CVEs -RUN apk add "libcrypto3>=3.0.8-r4" "libssl3>=3.0.8-r4" +RUN apk add "libcrypto3>=3.1.1-r2" "libssl3>=3.1.1-r2" VOLUME /data /etc/nginx diff --git a/src/autoconf/IngressController.py b/src/autoconf/IngressController.py index 4856b8fd2..ad7b71542 100644 --- a/src/autoconf/IngressController.py +++ b/src/autoconf/IngressController.py @@ -1,26 +1,24 @@ -from os import getenv +#!/usr/bin/python3 + from time import sleep from traceback import format_exc +from typing import List from kubernetes import client, config, watch from kubernetes.client.exceptions import ApiException from threading import Thread, Lock from Controller import Controller -from ConfigCaller import ConfigCaller -from logger import setup_logger -class IngressController(Controller, ConfigCaller): +class IngressController(Controller): def __init__(self): - Controller.__init__(self, "kubernetes") - ConfigCaller.__init__(self) + self.__internal_lock = Lock() + super().__init__("kubernetes") config.load_incluster_config() self.__corev1 = client.CoreV1Api() self.__networkingv1 = client.NetworkingV1Api() - self.__internal_lock = Lock() - self.__logger = setup_logger("Ingress-controller", getenv("LOG_LEVEL", "INFO")) - def _get_controller_instances(self): + def _get_controller_instances(self) -> list: return [ pod for pod in self.__corev1.list_pod_for_all_namespaces(watch=False).items @@ -30,10 +28,12 @@ class IngressController(Controller, ConfigCaller): ) ] - def _to_instances(self, controller_instance): + def _to_instances(self, controller_instance) -> List[dict]: instance = {} instance["name"] = controller_instance.metadata.name - instance["hostname"] = controller_instance.status.pod_ip + instance["hostname"] = ( + controller_instance.status.pod_ip or controller_instance.metadata.name + ) health = False if controller_instance.status.conditions: for condition in controller_instance.status.conditions: @@ -48,7 +48,9 @@ class IngressController(Controller, ConfigCaller): pod = container break if not pod: - self.__logger.warning(f"Missing container bunkerweb in pod {controller_instance.metadata.name}") + self._logger.warning( + f"Missing container bunkerweb in pod {controller_instance.metadata.name}" + ) else: for env in pod.env: instance["env"][env.name] = env.value or "" @@ -65,18 +67,18 @@ class IngressController(Controller, ConfigCaller): instance["env"][variable] = value return [instance] - def _get_controller_services(self): + def _get_controller_services(self) -> list: return self.__networkingv1.list_ingress_for_all_namespaces(watch=False).items - def _to_services(self, controller_service): + def _to_services(self, controller_service) -> List[dict]: if not controller_service.spec or not controller_service.spec.rules: return [] - + namespace = controller_service.metadata.namespace services = [] # parse rules for rule in controller_service.spec.rules: if not rule.host: - self.__logger.warning( + self._logger.warning( "Ignoring unsupported ingress rule without host.", ) continue @@ -88,38 +90,38 @@ class IngressController(Controller, ConfigCaller): location = 1 for path in rule.http.paths: if not path.path: - self.__logger.warning( + self._logger.warning( "Ignoring unsupported ingress rule without path.", ) continue elif not path.backend.service: - self.__logger.warning( + self._logger.warning( "Ignoring unsupported ingress rule without backend service.", ) continue elif not path.backend.service.port: - self.__logger.warning( + self._logger.warning( "Ignoring unsupported ingress rule without backend service port.", ) continue elif not path.backend.service.port.number: - self.__logger.warning( + self._logger.warning( "Ignoring unsupported ingress rule without backend service port number.", ) continue service_list = self.__corev1.list_service_for_all_namespaces( watch=False, - field_selector=f"metadata.name={path.backend.service.name}", + field_selector=f"metadata.name={path.backend.service.name},metadata.namespace={namespace}", ).items if not service_list: - self.__logger.warning( + self._logger.warning( f"Ignoring ingress rule with service {path.backend.service.name} : service not found.", ) continue - reverse_proxy_host = f"http://{path.backend.service.name}.{service_list[0].metadata.namespace}.svc.cluster.local:{path.backend.service.port.number}" + reverse_proxy_host = f"http://{path.backend.service.name}.{namespace}.svc.cluster.local:{path.backend.service.port.number}" service.update( { "USE_REVERSE_PROXY": "yes", @@ -132,7 +134,7 @@ class IngressController(Controller, ConfigCaller): # parse tls if controller_service.spec.tls: # TODO: support tls - self.__logger.warning("Ignoring unsupported tls.") + self._logger.warning("Ignoring unsupported tls.") # parse annotations if controller_service.metadata.annotations: @@ -145,15 +147,15 @@ class IngressController(Controller, ConfigCaller): continue variable = annotation.replace("bunkerweb.io/", "", 1) - server_name = service["SERVER_NAME"].split(" ")[0] + server_name = service["SERVER_NAME"].strip().split(" ")[0] if not variable.startswith(f"{server_name}_"): continue variable = variable.replace(f"{server_name}_", "", 1) - if self._is_multisite_setting(variable): + if self._is_setting_context(variable, "multisite"): service[variable] = value return services - def _get_static_services(self): + def _get_static_services(self) -> List[dict]: services = [] variables = {} for instance in self.__corev1.list_pod_for_all_namespaces(watch=False).items: @@ -168,12 +170,10 @@ class IngressController(Controller, ConfigCaller): if container.name == "bunkerweb": pod = container break - if not pod : + if not pod: continue - variables = { - env.name: env.value or "" for env in pod.env - } + variables = {env.name: env.value or "" for env in pod.env} if "SERVER_NAME" in variables and variables["SERVER_NAME"].strip(): for server_name in variables["SERVER_NAME"].strip().split(" "): @@ -181,14 +181,14 @@ class IngressController(Controller, ConfigCaller): for variable, value in variables.items(): prefix = variable.split("_")[0] real_variable = variable.replace(f"{prefix}_", "", 1) - if prefix == server_name and self._is_multisite_setting( - real_variable + if prefix == server_name and self._is_setting_context( + real_variable, "multisite" ): service[real_variable] = value services.append(service) return services - def get_configs(self): + def get_configs(self) -> dict: configs = {config_type: {} for config_type in self._supported_config_types} for configmap in self.__corev1.list_config_map_for_all_namespaces( watch=False @@ -201,12 +201,12 @@ class IngressController(Controller, ConfigCaller): config_type = configmap.metadata.annotations["bunkerweb.io/CONFIG_TYPE"] if config_type not in self._supported_config_types: - self.__logger.warning( + self._logger.warning( f"Ignoring unsupported CONFIG_TYPE {config_type} for ConfigMap {configmap.metadata.name}", ) continue elif not configmap.data: - self.__logger.warning( + self._logger.warning( f"Ignoring blank ConfigMap {configmap.metadata.name}", ) continue @@ -215,7 +215,7 @@ class IngressController(Controller, ConfigCaller): if not self._is_service_present( configmap.metadata.annotations["bunkerweb.io/CONFIG_SITE"] ): - self.__logger.warning( + self._logger.warning( f"Ignoring config {configmap.metadata.name} because {configmap.metadata.annotations['bunkerweb.io/CONFIG_SITE']} doesn't exist", ) continue @@ -250,46 +250,41 @@ class IngressController(Controller, ConfigCaller): self._instances = self.get_instances() self._services = self.get_services() self._configs = self.get_configs() - if not self._config.update_needed( + if not self.update_needed( self._instances, self._services, configs=self._configs ): self.__internal_lock.release() locked = False continue - self.__logger.info( + self._logger.info( f"Catched kubernetes event ({watch_type}), deploying new configuration ...", ) try: ret = self.apply_config() if not ret: - self.__logger.error( + self._logger.error( "Error while deploying new configuration ...", ) else: - self.__logger.info( + self._logger.info( "Successfully deployed new configuration 🚀", ) - if not self._config._db.is_autoconf_loaded(): - ret = self._config._db.set_autoconf_load(True) - if ret: - self.__logger.warning( - f"Can't set autoconf loaded metadata to true in database: {ret}", - ) + self._set_autoconf_load_db() except: - self.__logger.error( + self._logger.error( f"Exception while deploying new configuration :\n{format_exc()}", ) self.__internal_lock.release() locked = False except ApiException as e: if e.status != 410: - self.__logger.error( + self._logger.error( f"API exception while reading k8s event (type = {watch_type}) :\n{format_exc()}", ) error = True except: - self.__logger.error( + self._logger.error( f"Unknown exception while reading k8s event (type = {watch_type}) :\n{format_exc()}", ) error = True @@ -299,13 +294,11 @@ class IngressController(Controller, ConfigCaller): locked = False if error is True: - self.__logger.warning("Got exception, retrying in 10 seconds ...") + self._logger.warning("Got exception, retrying in 10 seconds ...") sleep(10) - def apply_config(self): - return self._config.apply( - self._instances, self._services, configs=self._configs - ) + def apply_config(self) -> bool: + return self.apply(self._instances, self._services, configs=self._configs) def process_events(self): self._set_autoconf_load_db() diff --git a/src/autoconf/SwarmController.py b/src/autoconf/SwarmController.py index f6095ef7a..d7cf99fcc 100644 --- a/src/autoconf/SwarmController.py +++ b/src/autoconf/SwarmController.py @@ -1,30 +1,29 @@ -from os import getenv +#!/usr/bin/python3 + from time import sleep from traceback import format_exc from threading import Thread, Lock +from typing import Any, Dict, List from docker import DockerClient from base64 import b64decode +from docker.models.services import Service from Controller import Controller -from ConfigCaller import ConfigCaller -from logger import setup_logger -class SwarmController(Controller, ConfigCaller): +class SwarmController(Controller): def __init__(self, docker_host): - Controller.__init__(self, "swarm") - ConfigCaller.__init__(self) + super().__init__("swarm") self.__client = DockerClient(base_url=docker_host) self.__internal_lock = Lock() - self.__logger = setup_logger("Swarm-controller", getenv("LOG_LEVEL", "INFO")) - def _get_controller_instances(self): + def _get_controller_instances(self) -> List[Service]: return self.__client.services.list(filters={"label": "bunkerweb.INSTANCE"}) - def _get_controller_services(self): + def _get_controller_services(self) -> List[Service]: return self.__client.services.list(filters={"label": "bunkerweb.SERVER_NAME"}) - def _to_instances(self, controller_instance): + def _to_instances(self, controller_instance) -> List[dict]: instances = [] instance_env = {} for env in controller_instance.attrs["Spec"]["TaskTemplate"]["ContainerSpec"][ @@ -48,18 +47,18 @@ class SwarmController(Controller, ConfigCaller): ) return instances - def _to_services(self, controller_service): + def _to_services(self, controller_service) -> List[dict]: service = {} for variable, value in controller_service.attrs["Spec"]["Labels"].items(): if not variable.startswith("bunkerweb."): continue real_variable = variable.replace("bunkerweb.", "", 1) - if not self._is_multisite_setting(real_variable): + if not self._is_setting_context(real_variable, "multisite"): continue service[real_variable] = value return [service] - def _get_static_services(self): + def _get_static_services(self) -> List[dict]: services = [] variables = {} for instance in self.__client.services.list( @@ -81,14 +80,14 @@ class SwarmController(Controller, ConfigCaller): for variable, value in variables.items(): prefix = variable.split("_")[0] real_variable = variable.replace(f"{prefix}_", "", 1) - if prefix == server_name and self._is_multisite_setting( - real_variable + if prefix == server_name and self._is_setting_context( + real_variable, "multisite" ): service[real_variable] = value services.append(service) return services - def get_configs(self): + def get_configs(self) -> Dict[str, Dict[str, Any]]: configs = {} for config_type in self._supported_config_types: configs[config_type] = {} @@ -106,7 +105,7 @@ class SwarmController(Controller, ConfigCaller): config_type = config.attrs["Spec"]["Labels"]["bunkerweb.CONFIG_TYPE"] config_name = config.name if config_type not in self._supported_config_types: - self.__logger.warning( + self._logger.warning( f"Ignoring unsupported CONFIG_TYPE {config_type} for Config {config_name}", ) continue @@ -115,7 +114,7 @@ class SwarmController(Controller, ConfigCaller): if not self._is_service_present( config.attrs["Spec"]["Labels"]["bunkerweb.CONFIG_SITE"] ): - self.__logger.warning( + self._logger.warning( f"Ignoring config {config_name} because {config.attrs['Spec']['Labels']['bunkerweb.CONFIG_SITE']} doesn't exist", ) continue @@ -127,10 +126,8 @@ class SwarmController(Controller, ConfigCaller): ) return configs - def apply_config(self): - return self._config.apply( - self._instances, self._services, configs=self._configs - ) + def apply_config(self) -> bool: + return self.apply(self._instances, self._services, configs=self._configs) def __event(self, event_type): while True: @@ -146,31 +143,31 @@ class SwarmController(Controller, ConfigCaller): self._instances = self.get_instances() self._services = self.get_services() self._configs = self.get_configs() - if not self._config.update_needed( + if not self.update_needed( self._instances, self._services, configs=self._configs ): self.__internal_lock.release() locked = False continue - self.__logger.info( + self._logger.info( f"Catched Swarm event ({event_type}), deploying new configuration ..." ) if not self.apply_config(): - self.__logger.error( + self._logger.error( "Error while deploying new configuration" ) else: - self.__logger.info( + self._logger.info( "Successfully deployed new configuration 🚀", ) except: - self.__logger.error( + self._logger.error( f"Exception while processing Swarm event ({event_type}) :\n{format_exc()}" ) self.__internal_lock.release() locked = False except: - self.__logger.error( + self._logger.error( f"Exception while reading Swarm event ({event_type}) :\n{format_exc()}", ) error = True @@ -179,7 +176,7 @@ class SwarmController(Controller, ConfigCaller): self.__internal_lock.release() locked = False if error is True: - self.__logger.warning("Got exception, retrying in 10 seconds ...") + self._logger.warning("Got exception, retrying in 10 seconds ...") sleep(10) def process_events(self): diff --git a/src/autoconf/main.py b/src/autoconf/main.py index c9753c59a..7a69468d3 100644 --- a/src/autoconf/main.py +++ b/src/autoconf/main.py @@ -1,21 +1,20 @@ #!/usr/bin/python3 -from os import _exit, getenv +from os import _exit, getenv, sep +from os.path import join from signal import SIGINT, SIGTERM, signal from sys import exit as sys_exit, path as sys_path from traceback import format_exc from pathlib import Path -sys_path.extend( - ( - "/usr/share/bunkerweb/deps/python", - "/usr/share/bunkerweb/utils", - "/usr/share/bunkerweb/api", - "/usr/share/bunkerweb/db", - ) -) +for deps_path in [ + join(sep, "usr", "share", "bunkerweb", *paths) + for paths in (("deps", "python"), ("utils",), ("api",), ("db",)) +]: + if deps_path not in sys_path: + sys_path.append(deps_path) -from logger import setup_logger +from logger import setup_logger # type: ignore from SwarmController import SwarmController from IngressController import IngressController from DockerController import DockerController @@ -70,12 +69,11 @@ try: _exit(1) # Process events - Path("/var/tmp/bunkerweb/autoconf.healthy").write_text("ok") + Path(sep, "var", "tmp", "bunkerweb", "autoconf.healthy").write_text("ok") logger.info("Processing events ...") controller.process_events() - except: logger.error(f"Exception while running autoconf :\n{format_exc()}") sys_exit(1) finally: - Path("/var/tmp/bunkerweb/autoconf.healthy").unlink(missing_ok=True) + Path(sep, "var", "tmp", "bunkerweb", "autoconf.healthy").unlink(missing_ok=True) diff --git a/src/bw/Dockerfile b/src/bw/Dockerfile index a634081ad..e1e917612 100644 --- a/src/bw/Dockerfile +++ b/src/bw/Dockerfile @@ -1,26 +1,32 @@ FROM nginx:1.24.0-alpine AS builder +# Install temporary requirements for the dependencies +RUN apk add --no-cache --virtual .build-deps bash autoconf libtool automake geoip-dev g++ gcc curl-dev libxml2-dev pcre-dev make linux-headers musl-dev gd-dev gnupg brotli-dev openssl-dev patch readline-dev + # Copy dependencies sources folder COPY src/deps /tmp/bunkerweb/deps # Compile and install dependencies -RUN apk add --no-cache --virtual .build-deps bash autoconf libtool automake geoip-dev g++ gcc curl-dev libxml2-dev pcre-dev make linux-headers musl-dev gd-dev gnupg brotli-dev openssl-dev patch readline-dev && \ - mkdir -p /usr/share/bunkerweb/deps && \ +RUN mkdir -p /usr/share/bunkerweb/deps && \ chmod +x /tmp/bunkerweb/deps/install.sh && \ - bash /tmp/bunkerweb/deps/install.sh && \ - apk del .build-deps + bash /tmp/bunkerweb/deps/install.sh + +# Clean up temporary dependencies +RUN apk del .build-deps && \ + rm -rf /var/cache/apk/* # Copy python requirements COPY src/common/gen/requirements.txt /usr/share/bunkerweb/deps/requirements.txt # Install python requirements RUN apk add --no-cache --virtual .build-deps py3-pip && \ - pip install --no-cache-dir --upgrade pip && \ - pip install wheel && \ mkdir -p /usr/share/bunkerweb/deps/python && \ export MAKEFLAGS="-j$(nproc)" && \ + pip install --no-cache-dir --upgrade pip && \ + pip install --no-cache-dir --upgrade pip-tools wheel setuptools && \ pip install --no-cache-dir --require-hashes --target /usr/share/bunkerweb/deps/python -r /usr/share/bunkerweb/deps/requirements.txt && \ - apk del .build-deps + apk del .build-deps && \ + rm -rf /var/cache/apk/* # Copy files # can't exclude deps from . so we are copying everything by hand @@ -51,25 +57,23 @@ COPY --from=builder --chown=0:101 /usr/share/bunkerweb /usr/share/bunkerweb RUN apk add --no-cache pcre bash python3 && \ cp /usr/share/bunkerweb/helpers/bwcli /usr/bin/ && \ mkdir -p /var/tmp/bunkerweb && \ + mkdir -p /var/run/bunkerweb && \ + mkdir -p /var/log/bunkerweb && \ mkdir -p /var/www/html && \ mkdir -p /etc/bunkerweb && \ mkdir -p /data/cache && ln -s /data/cache /var/cache/bunkerweb && \ for dir in $(echo "configs plugins") ; do mkdir -p "/data/${dir}" && ln -s "/data/${dir}" "/etc/bunkerweb/${dir}" ; done && \ for dir in $(echo "configs/http configs/stream configs/server-http configs/server-stream configs/default-server-http configs/default-server-stream configs/modsec configs/modsec-crs") ; do mkdir "/data/${dir}" ; done && \ - chown -R root:nginx /data && \ - chmod -R 770 /data && \ - chown -R root:nginx /var/cache/bunkerweb /etc/bunkerweb /var/tmp/bunkerweb /usr/bin/bwcli && \ - chmod 770 /var/cache/bunkerweb /var/tmp/bunkerweb && \ + chown -R root:nginx /data /etc/nginx /var/cache/bunkerweb /etc/bunkerweb /var/tmp/bunkerweb /var/run/bunkerweb /var/log/bunkerweb /usr/bin/bwcli && \ + chmod -R 770 /data /etc/nginx /var/cache/bunkerweb /var/tmp/bunkerweb /var/log/bunkerweb /var/run/bunkerweb && \ chmod 750 /usr/share/bunkerweb/cli/main.py /usr/share/bunkerweb/gen/main.py /usr/share/bunkerweb/helpers/*.sh /usr/share/bunkerweb/entrypoint.sh /usr/bin/bwcli /usr/share/bunkerweb/deps/python/bin/* && \ - chown -R root:nginx /etc/nginx && \ - chmod -R 770 /etc/nginx && \ - rm -f /var/log/nginx/* && \ - ln -s /proc/1/fd/2 /var/log/nginx/error.log && \ - ln -s /proc/1/fd/2 /var/log/nginx/modsec_audit.log && \ - ln -s /proc/1/fd/1 /var/log/nginx/access.log + rm -f /var/log/bunkerweb/* && \ + ln -s /proc/1/fd/2 /var/log/bunkerweb/error.log && \ + ln -s /proc/1/fd/2 /var/log/bunkerweb/modsec_audit.log && \ + ln -s /proc/1/fd/1 /var/log/bunkerweb/access.log # Fix CVEs -RUN apk add "libcrypto3>=3.0.8-r4" "libssl3>=3.0.8-r4" "curl>=8.1.0-r0" "libcurl>=8.1.0-r0" +RUN apk add "libx11>=1.8.4-r1" "tiff>=4.4.0-r4" "libcrypto3>=3.0.9-r2" "libssl3>=3.0.9-r2" "nghttp2-libs>=1.51.0-r1" VOLUME /data /etc/nginx diff --git a/src/bw/entrypoint.sh b/src/bw/entrypoint.sh index 1331a3482..6721dc4e0 100644 --- a/src/bw/entrypoint.sh +++ b/src/bw/entrypoint.sh @@ -21,7 +21,7 @@ trap "trap_exit" TERM INT QUIT # trap SIGHUP function trap_reload() { log "ENTRYPOINT" "â„šī¸" "Catched reload operation" - if [ -f /var/tmp/bunkerweb/nginx.pid ] ; then + if [ -f /var/run/bunkerweb/nginx.pid ] ; then log "ENTRYPOINT" "â„šī¸" "Reloading nginx ..." nginx -s reload if [ $? -eq 0 ] ; then @@ -39,7 +39,7 @@ if [ -f "/etc/nginx/variables.env" ] ; then log "ENTRYPOINT" "âš ī¸ " "Looks like BunkerWeb has already been loaded, will not generate temp config" else # generate "temp" config - echo -e "IS_LOADING=yes\nSERVER_NAME=\nAPI_HTTP_PORT=${API_HTTP_PORT:-5000}\nAPI_SERVER_NAME=${API_SERVER_NAME:-bwapi}\nAPI_WHITELIST_IP=${API_WHITELIST_IP:-127.0.0.0/8}\nUSE_REAL_IP=${USE_REAL_IP:-no}\nUSE_REAL_IP=${USE_REAL_IP:-no}\nUSE_PROXY_PROTOCOL=${USE_PROXY_PROTOCOL:-no}\nREAL_IP_FROM=${REAL_IP_FROM:-192.168.0.0/16 172.16.0.0/12 10.0.0.0/8}\nREAL_IP_HEADER=${REAL_IP_HEADER:-X-Forwarded-For}" > /tmp/variables.env + echo -e "IS_LOADING=yes\nSERVER_NAME=\nAPI_HTTP_PORT=${API_HTTP_PORT:-5000}\nAPI_SERVER_NAME=${API_SERVER_NAME:-bwapi}\nAPI_WHITELIST_IP=${API_WHITELIST_IP:-127.0.0.0/8}\nUSE_REAL_IP=${USE_REAL_IP:-no}\nUSE_PROXY_PROTOCOL=${USE_PROXY_PROTOCOL:-no}\nREAL_IP_FROM=${REAL_IP_FROM:-192.168.0.0/16 172.16.0.0/12 10.0.0.0/8}\nREAL_IP_HEADER=${REAL_IP_HEADER:-X-Forwarded-For}\nHTTP_PORT=${HTTP_PORT:-8080}\nHTTPS_PORT=${HTTPS_PORT:-8443}" > /tmp/variables.env python3 /usr/share/bunkerweb/gen/main.py --variables /tmp/variables.env fi @@ -50,7 +50,7 @@ pid="$!" # wait while nginx is running wait "$pid" -while [ -f "/var/tmp/bunkerweb/nginx.pid" ] ; do +while [ -f "/var/run/bunkerweb/nginx.pid" ] ; do wait "$pid" done diff --git a/src/bw/lua/bunkerweb/api.lua b/src/bw/lua/bunkerweb/api.lua index 3139ba6b0..a6d615a08 100644 --- a/src/bw/lua/bunkerweb/api.lua +++ b/src/bw/lua/bunkerweb/api.lua @@ -1,11 +1,11 @@ local class = require "middleclass" local datastore = require "bunkerweb.datastore" local utils = require "bunkerweb.utils" -local logger = require "bunkerweb.logger" +local logger = require "bunkerweb.logger" local cjson = require "cjson" local upload = require "resty.upload" -local rsignal = require "resty.signal" -local process = require "ngx.process" +local rsignal = require "resty.signal" +local process = require "ngx.process" local api = class("api") @@ -14,6 +14,16 @@ api.global = { GET = {}, POST = {}, PUT = {}, DELETE = {} } function api:initialize() self.datastore = datastore:new() self.logger = logger:new("API") + self.ctx = ngx.ctx + local data, err = utils.get_variable("API_WHITELIST_IP", false) + self.ips = {} + if not data then + self.logger.log(ngx.ERR, "can't get API_WHITELIST_IP variable : " .. err) + else + for ip in data:gmatch("%S+") do + table.insert(self.ips, ip) + end + end end function api:log_cmd(cmd, status, stdout, stderr) @@ -71,17 +81,17 @@ api.global.POST["^/stop$"] = function(self) end api.global.POST["^/confs$"] = function(self) - local tmp = "/var/tmp/bunkerweb/api_" .. ngx.ctx.bw.uri:sub(2) .. ".tar.gz" - local destination = "/usr/share/bunkerweb/" .. ngx.ctx.bw.uri:sub(2) - if ngx.ctx.bw.uri == "/confs" then + local tmp = "/var/tmp/bunkerweb/api_" .. self.ctx.bw.uri:sub(2) .. ".tar.gz" + local destination = "/usr/share/bunkerweb/" .. self.ctx.bw.uri:sub(2) + if self.ctx.bw.uri == "/confs" then destination = "/etc/nginx" - elseif ngx.ctx.bw.uri == "/data" then + elseif self.ctx.bw.uri == "/data" then destination = "/data" - elseif ngx.ctx.bw.uri == "/cache" then + elseif self.ctx.bw.uri == "/cache" then destination = "/var/cache/bunkerweb" - elseif ngx.ctx.bw.uri == "/custom_configs" then + elseif self.ctx.bw.uri == "/custom_configs" then destination = "/etc/bunkerweb/configs" - elseif ngx.ctx.bw.uri == "/plugins" then + elseif self.ctx.bw.uri == "/plugins" then destination = "/etc/bunkerweb/plugins" end local form, err = upload:new(4096) @@ -185,21 +195,25 @@ api.global.GET["^/bans$"] = function(self) return self:response(ngx.HTTP_OK, "success", data) end -function api:is_allowed_ip() - local data, err = self.datastore:get("api_whitelist_ip") - if not data then - return false, "can't access api_allowed_ips in datastore" +api.global.GET["^/variables$"] = function(self) + local variables, err = datastore:get('variables', true) + if not variables then + return self:response(ngx.HTTP_INTERNAL_SERVER_ERROR, "error", "can't access variables from datastore : " .. err) end - if utils.is_ip_in_networks(ngx.ctx.bw.remote_addr, cjson.decode(data)) then + return self:response(ngx.HTTP_OK, "success", variables) +end + +function api:is_allowed_ip() + if utils.is_ip_in_networks(self.ctx.bw.remote_addr, self.ips) then return true, "ok" end return false, "IP is not in API_WHITELIST_IP" end function api:do_api_call() - if self.global[ngx.ctx.bw.request_method] ~= nil then - for uri, api_fun in pairs(self.global[ngx.ctx.bw.request_method]) do - if string.match(ngx.ctx.bw.uri, uri) then + if self.global[self.ctx.bw.request_method] ~= nil then + for uri, api_fun in pairs(self.global[self.ctx.bw.request_method]) do + if string.match(self.ctx.bw.uri, uri) then local status, resp = api_fun(self) local ret = true if status ~= ngx.HTTP_OK then @@ -215,17 +229,16 @@ function api:do_api_call() end end end - local list, err = self.datastore:get("plugins") + local list, err = self.datastore:get("plugins", true) if not list then local status, resp = self:response(ngx.HTTP_INTERNAL_SERVER_ERROR, "error", "can't list loaded plugins : " .. err) - return false, resp["msg"], ngx.HTTP_INTERNAL_SERVER_ERROR, resp + return false, resp["msg"], ngx.HTTP_INTERNAL_SERVER_ERROR, cjson.encode(resp) end - list = cjson.decode(list) for i, plugin in ipairs(list) do if pcall(require, plugin.id .. "/" .. plugin.id) then local plugin_lua = require(plugin.id .. "/" .. plugin.id) if plugin_lua.api ~= nil then - local matched, status, resp = plugin_lua.api() + local matched, status, resp = plugin_lua:api(self.ctx) if matched then local ret = true if status ~= ngx.HTTP_OK then diff --git a/src/bw/lua/bunkerweb/cachestore.lua b/src/bw/lua/bunkerweb/cachestore.lua index 0041af7df..4b1bd5aa7 100644 --- a/src/bw/lua/bunkerweb/cachestore.lua +++ b/src/bw/lua/bunkerweb/cachestore.lua @@ -1,16 +1,16 @@ -local mlcache = require "resty.mlcache" +local mlcache = require "resty.mlcache" local clusterstore = require "bunkerweb.clusterstore" -local logger = require "bunkerweb.logger" -local utils = require "bunkerweb.utils" -local class = require "middleclass" -local cachestore = class("cachestore") +local logger = require "bunkerweb.logger" +local utils = require "bunkerweb.utils" +local class = require "middleclass" +local cachestore = class("cachestore") -- Instantiate mlcache object at module level (which will be cached when running init phase) -- TODO : custom settings -local shm = "cachestore" -local ipc_shm = "cachestore_ipc" -local shm_miss = "cachestore_miss" -local shm_locks = "cachestore_locks" +local shm = "cachestore" +local ipc_shm = "cachestore_ipc" +local shm_miss = "cachestore_miss" +local shm_locks = "cachestore_locks" if not ngx.shared.cachestore then shm = "cachestore_stream" ipc_shm = "cachestore_ipc_stream" @@ -42,7 +42,8 @@ if not cache then module_logger:log(ngx.ERR, "can't instantiate mlcache : " .. err) end -function cachestore:initialize(use_redis, new_cs) +function cachestore:initialize(use_redis, new_cs, ctx) + self.ctx = ctx self.cache = cache self.use_redis = use_redis or false self.logger = module_logger @@ -50,7 +51,7 @@ function cachestore:initialize(use_redis, new_cs) self.clusterstore = clusterstore:new(false) self.shared_cs = false else - self.clusterstore = utils.get_ctx_obj("clusterstore") + self.clusterstore = utils.get_ctx_obj("clusterstore", self.ctx) self.shared_cs = true end end diff --git a/src/bw/lua/bunkerweb/clusterstore.lua b/src/bw/lua/bunkerweb/clusterstore.lua index 1f96aabc3..d6528c3a0 100644 --- a/src/bw/lua/bunkerweb/clusterstore.lua +++ b/src/bw/lua/bunkerweb/clusterstore.lua @@ -77,7 +77,8 @@ function clusterstore:close() if self.redis_client then -- Equivalent to close but keep a pool of connections if self.pool then - local ok, err = self.redis_client:set_keepalive(tonumber(self.variables["REDIS_KEEPALIVE_IDLE"]), tonumber(self.variables["REDIS_KEEPALIVE_POOL"])) + local ok, err = self.redis_client:set_keepalive(tonumber(self.variables["REDIS_KEEPALIVE_IDLE"]), + tonumber(self.variables["REDIS_KEEPALIVE_POOL"])) self.redis_client = nil if not ok then require "bunkerweb.logger":new("clusterstore-close"):log(ngx.ERR, err) diff --git a/src/bw/lua/bunkerweb/datastore.lua b/src/bw/lua/bunkerweb/datastore.lua index 3fee5d305..6be6b4c4a 100644 --- a/src/bw/lua/bunkerweb/datastore.lua +++ b/src/bw/lua/bunkerweb/datastore.lua @@ -1,6 +1,13 @@ local class = require "middleclass" +local lrucache = require "resty.lrucache" local datastore = class("datastore") +local lru, err = lrucache.new(100000) +if not lru then + require "bunkerweb.logger":new("DATASTORE"):log(ngx.ERR, + "failed to instantiate LRU cache : " .. (err or "unknown error")) +end + function datastore:initialize() self.dict = ngx.shared.datastore if not self.dict then @@ -8,7 +15,11 @@ function datastore:initialize() end end -function datastore:get(key) +function datastore:get(key, worker) + if worker then + local value, err = lru:get(key) + return value, err or "not found" + end local value, err = self.dict:get(key) if not value and not err then err = "not found" @@ -16,21 +27,35 @@ function datastore:get(key) return value, err end -function datastore:set(key, value, exptime) +function datastore:set(key, value, exptime, worker) + if worker then + lru:set(key, value, exptime) + return true, "success" + end exptime = exptime or 0 return self.dict:safe_set(key, value, exptime) end -function datastore:delete(key) +function datastore:delete(key, worker) + if worker then + lru:delete(key) + return true, "success" + end self.dict:delete(key) return true, "success" end -function datastore:keys() +function datastore:keys(worker) + if worker then + return lru:keys(0) + end return self.dict:get_keys(0) end function datastore:ttl(key) + if worker then + return false, "not supported by LRU" + end local ttl, err = self.dict:ttl(key) if not ttl then return false, err @@ -38,8 +63,13 @@ function datastore:ttl(key) return true, ttl end -function datastore:delete_all(pattern) - local keys = self.dict:get_keys(0) +function datastore:delete_all(pattern, worker) + local keys = {} + if worker then + keys = lru:keys(0) + else + keys = self.dict:get_keys(0) + end for i, key in ipairs(keys) do if key:match(pattern) then self.dict:delete(key) @@ -48,4 +78,8 @@ function datastore:delete_all(pattern) return true, "success" end +function datastore:flush_lru() + lru:flush_all() +end + return datastore diff --git a/src/bw/lua/bunkerweb/helpers.lua b/src/bw/lua/bunkerweb/helpers.lua index e2248039b..cc4d11462 100644 --- a/src/bw/lua/bunkerweb/helpers.lua +++ b/src/bw/lua/bunkerweb/helpers.lua @@ -108,9 +108,9 @@ helpers.require_plugin = function(id) return plugin_lua, "require() call successful for plugin " .. id end -helpers.new_plugin = function(plugin_lua) +helpers.new_plugin = function(plugin_lua, ctx) -- Require call - local ok, plugin_obj = pcall(plugin_lua.new, plugin_lua) + local ok, plugin_obj = pcall(plugin_lua.new, plugin_lua, ctx) if not ok then return false, "new error for plugin " .. plugin_lua.name .. " : " .. plugin_obj end @@ -148,8 +148,9 @@ end helpers.fill_ctx = function() -- Return errors as table local errors = {} + local ctx = ngx.ctx -- Check if ctx is already filled - if not ngx.ctx.bw then + if not ctx.bw then -- Instantiate bw table local data = {} -- Common vars @@ -158,14 +159,20 @@ helpers.fill_ctx = function() data.kind = "stream" end data.remote_addr = ngx.var.remote_addr - data.uri = ngx.var.uri - data.request_uri = ngx.var.request_uri - data.request_method = ngx.var.request_method - data.http_user_agent = ngx.var.http_user_agent - data.http_host = ngx.var.http_host data.server_name = ngx.var.server_name - data.http_content_type = ngx.var.http_content_type - data.http_origin = ngx.var.http_origin + if data.kind == "http" then + data.uri = ngx.var.uri + data.request_uri = ngx.var.request_uri + data.request_method = ngx.var.request_method + data.http_user_agent = ngx.var.http_user_agent + data.http_host = ngx.var.http_host + data.server_name = ngx.var.server_name + data.http_content_type = ngx.var.http_content_type + data.http_content_length = ngx.var.http_content_length + data.http_origin = ngx.var.http_origin + data.http_version = ngx.req.http_version() + data.scheme = ngx.var.scheme + end -- IP data : global local ip_is_global, err = utils.ip_is_global(data.remote_addr) if ip_is_global == nil then @@ -180,17 +187,76 @@ helpers.fill_ctx = function() data.integration = utils.get_integration() data.version = utils.get_version() -- Fill ctx - ngx.ctx.bw = data + ctx.bw = data end -- Always create new objects for current phases in case of cosockets local use_redis, err = utils.get_variable("USE_REDIS", false) if not use_redis then table.insert(errors, "can't get variable from datastore : " .. err) end - ngx.ctx.bw.datastore = require "bunkerweb.datastore":new() - ngx.ctx.bw.clusterstore = require "bunkerweb.clusterstore":new() - ngx.ctx.bw.cachestore = require "bunkerweb.cachestore":new(use_redis == "yes") - return true, "ctx filled", errors + ctx.bw.datastore = require "bunkerweb.datastore":new() + ctx.bw.clusterstore = require "bunkerweb.clusterstore":new() + ctx.bw.cachestore = require "bunkerweb.cachestore":new(use_redis == "yes") + return true, "ctx filled", errors, ctx +end + +function helpers.load_variables(all_variables, plugins) + -- Extract settings from plugins and global ones + local all_settings = {} + for i, plugin in ipairs(plugins) do + if plugin.settings then + for setting, data in pairs(plugin.settings) do + all_settings[setting] = data + end + end + end + local file = io.open("/usr/share/bunkerweb/settings.json") + if not file then + return false, "can't open settings.json" + end + local ok, settings = pcall(cjson.decode, file:read("*a")) + file:close() + if not ok then + return false, "invalid settings.json : " .. err + end + for setting, data in pairs(settings) do + all_settings[setting] = data + end + -- Extract vars + local variables = { ["global"] = {} } + local multisite = all_variables["MULTISITE"] == "yes" + local server_names = {} + if multisite then + for server_name in all_variables["SERVER_NAME"]:gmatch("%S+") do + variables[server_name] = {} + table.insert(server_names, server_name) + end + end + for setting, data in pairs(all_settings) do + if all_variables[setting] then + variables["global"][setting] = all_variables[setting] + end + if multisite then + for i, server_name in ipairs(server_names) do + local key = server_name .. "_" .. setting + if all_variables[key] then + variables[server_name][setting] = all_variables[key] + end + end + end + if data.multiple then + for variable, value in pairs(all_variables) do + local found, _, prefix = variable:find("^([^_]*)_?" .. setting .. "_[0-9]+$") + if found then + if multisite and prefix and prefix ~= "" then + variables[prefix][variable] = value + end + variables["global"][variable] = value + end + end + end + end + return true, variables end return helpers diff --git a/src/bw/lua/bunkerweb/plugin.lua b/src/bw/lua/bunkerweb/plugin.lua index b4e791134..3ad967e3e 100644 --- a/src/bw/lua/bunkerweb/plugin.lua +++ b/src/bw/lua/bunkerweb/plugin.lua @@ -1,18 +1,19 @@ -local class = require "middleclass" -local logger = require "bunkerweb.logger" -local datastore = require "bunkerweb.datastore" -local cachestore = require "bunkerweb.cachestore" +local class = require "middleclass" +local logger = require "bunkerweb.logger" +local datastore = require "bunkerweb.datastore" +local cachestore = require "bunkerweb.cachestore" local clusterstore = require "bunkerweb.clusterstore" -local utils = require "bunkerweb.utils" -local cjson = require "cjson" -local plugin = class("plugin") +local utils = require "bunkerweb.utils" +local cjson = require "cjson" +local plugin = class("plugin") -function plugin:initialize(id) +function plugin:initialize(id, ctx) -- Store common, values self.id = id local multisite = false local current_phase = ngx.get_phase() - for i, check_phase in ipairs({ "set", "access", "content", "header", "log", "preread", "log_stream", "log_default" }) do + for i, check_phase in ipairs({ "set", "access", "content", "header_filter", "log", "preread", "log_stream", + "log_default" }) do if current_phase == check_phase then multisite = true break @@ -21,35 +22,46 @@ function plugin:initialize(id) self.is_request = multisite -- Store common objets self.logger = logger:new(self.id) - local use_redis, err = utils.get_variable("USE_REDIS", false) - if not use_redis then - self.logger:log(ngx.ERR, err) - end - self.use_redis = use_redis == "yes" + local use_redis, err = utils.get_variable("USE_REDIS", false) + if not use_redis then + self.logger:log(ngx.ERR, err) + end + self.use_redis = use_redis == "yes" if self.is_request then - self.datastore = utils.get_ctx_obj("datastore") or datastore:new() - self.cachestore = utils.get_ctx_obj("cachestore") or cachestore:new(use_redis == "yes", true) - self.clusterstore = utils.get_ctx_obj("clusterstore") or clusterstore:new(false) + -- Store ctx + self.ctx = ctx or ngx.ctx + self.datastore = utils.get_ctx_obj("datastore", self.ctx) or datastore:new() + self.cachestore = utils.get_ctx_obj("cachestore", self.ctx) or cachestore:new(use_redis == "yes", true, self.ctx) + self.clusterstore = utils.get_ctx_obj("clusterstore", self.ctx) or clusterstore:new(false) else self.datastore = datastore:new() self.cachestore = cachestore:new(use_redis == "yes", true) self.clusterstore = clusterstore:new(false) end -- Get metadata - local encoded_metadata, err = self.datastore:get("plugin_" .. id) - if not encoded_metadata then + local metadata, err = self.datastore:get("plugin_" .. id, true) + if not metadata then self.logger:log(ngx.ERR, err) return end -- Store variables self.variables = {} - local metadata = cjson.decode(encoded_metadata) + self.multiples = {} for k, v in pairs(metadata.settings) do local value, err = utils.get_variable(k, v.context == "multisite" and multisite) if value == nil then self.logger:log(ngx.ERR, "can't get " .. k .. " variable : " .. err) end self.variables[k] = value + -- if v.multiple then + -- local multiples, err = utils.get_multiple_variables(k) + -- if not multiples then + -- self.logger:log(ngx.ERR, "can't get " .. k .. " multiple variable : " .. err) + -- self.multiples[k] = {} + -- else + -- self.multiples[k] = multiples + -- end + -- end end -- Is loading local is_loading, err = utils.get_variable("IS_LOADING", false) diff --git a/src/bw/lua/bunkerweb/utils.lua b/src/bw/lua/bunkerweb/utils.lua index 95c0ed7e1..dcf267f59 100644 --- a/src/bw/lua/bunkerweb/utils.lua +++ b/src/bw/lua/bunkerweb/utils.lua @@ -1,16 +1,16 @@ -local cdatastore = require "bunkerweb.datastore" -local mmdb = require "bunkerweb.mmdb" -local clogger = require "bunkerweb.logger" +local cdatastore = require "bunkerweb.datastore" +local mmdb = require "bunkerweb.mmdb" +local clogger = require "bunkerweb.logger" -local ipmatcher = require "resty.ipmatcher" -local resolver = require "resty.dns.resolver" -local session = require "resty.session" -local cjson = require "cjson" +local ipmatcher = require "resty.ipmatcher" +local resolver = require "resty.dns.resolver" +local session = require "resty.session" +local cjson = require "cjson" -local logger = clogger:new("UTILS") -local datastore = cdatastore:new() +local logger = clogger:new("UTILS") +local datastore = cdatastore:new() -local utils = {} +local utils = {} math.randomseed(os.time()) @@ -20,49 +20,32 @@ utils.get_variable = function(var, site_search) site_search = true end -- Get global value - local value, err = datastore:get("variable_" .. var) - if not value then - return nil, "can't access variable " .. var .. " from datastore : " .. err + local variables, err = datastore:get('variables', true) + if not variables then + return nil, "can't access variables from datastore : " .. err end + local value = variables["global"][var] -- Site search case - if site_search then - -- Check if multisite is set to yes - local multisite, err = datastore:get("variable_MULTISITE") - if not multisite then - return nil, "can't access variable MULTISITE from datastore : " .. err - end - -- Multisite case - if multisite == "yes" and ngx.var.server_name then - local value_site, err = datastore:get("variable_" .. ngx.var.server_name .. "_" .. var) - if value_site then - value = value_site - end - end + local multisite = site_search and variables["global"]["MULTISITE"] == "yes" and ngx.var.server_name ~= "_" + if multisite then + value = variables[ngx.var.server_name][var] end return value, "success" end utils.has_variable = function(var, value) -- Get global variable - local check_value, err = datastore:get("variable_" .. var) - if not value then - return nil, "Can't access variable " .. var .. " from datastore : " .. err - end - -- Check if multisite is set to yes - local multisite, err = datastore:get("variable_MULTISITE") - if not multisite then - return nil, "Can't access variable MULTISITE from datastore : " .. err + local variables, err = datastore:get('variables', true) + if not variables then + return nil, "can't access variables " .. var .. " from datastore : " .. err end -- Multisite case - if multisite == "yes" then - local servers, err = datastore:get("variable_SERVER_NAME") - if not servers then - return nil, "Can't access variable SERVER_NAME from datastore : " .. err - end + local multisite = variables["global"]["MULTISITE"] == "yes" + if multisite then + local servers = variables["global"]["SERVER_NAME"] -- Check each server for server in servers:gmatch("%S+") do - local check_value_site, err = datastore:get("variable_" .. server .. "_" .. var) - if check_value_site and check_value_site == value then + if variables[server][var] == value then return true, "success" end end @@ -70,30 +53,22 @@ utils.has_variable = function(var, value) return false, "success" end end - return check_value == value, "success" + return variables["global"][var] == value, "success" end utils.has_not_variable = function(var, value) -- Get global variable - local check_value, err = datastore:get("variable_" .. var) - if not value then - return nil, "Can't access variable " .. var .. " from datastore : " .. err - end - -- Check if multisite is set to yes - local multisite, err = datastore:get("variable_MULTISITE") - if not multisite then - return nil, "Can't access variable MULTISITE from datastore : " .. err + local variables, err = datastore:get('variables', true) + if not variables then + return nil, "can't access variables " .. var .. " from datastore : " .. err end -- Multisite case - if multisite == "yes" then - local servers, err = datastore:get("variable_SERVER_NAME") - if not servers then - return nil, "Can't access variable SERVER_NAME from datastore : " .. err - end + local multisite = variables["global"]["MULTISITE"] == "yes" + if multisite then + local servers = variables["global"]["SERVER_NAME"] -- Check each server for server in servers:gmatch("%S+") do - local check_value_site, err = datastore:get("variable_" .. server .. "_" .. var) - if check_value_site and check_value_site ~= value then + if variables[server][var] ~= "value" then return true, "success" end end @@ -101,33 +76,24 @@ utils.has_not_variable = function(var, value) return false, "success" end end - return check_value ~= value, "success" + return variables["global"][var] ~= value, "success" end utils.get_multiple_variables = function(vars) - -- Get all keys - local keys = datastore:keys() + local variables, err = datastore:get('variables', true) + if not variables then + return nil, "can't access variables " .. var .. " from datastore : " .. err + end local result = {} - -- Loop on keys - for i, key in ipairs(keys) do + -- Loop on scoped vars + for scope, scoped_vars in pairs(variables) do + result[scope] = {} -- Loop on vars - for j, var in ipairs(vars) do - -- Filter on good ones - local _, _, server, subvar = key:find("variable_(.*)_?(" .. var .. "_?%d*)") - if subvar then - if not server or server == "" then - server = "global" - else - server = server:sub(1, -2) + for variable, value in pairs(scoped_vars) do + for i, var in ipairs(vars) do + if variable:find("^" .. var .. "_?[0-9]*$") then + result[scope][variable] = value end - if result[server] == nil then - result[server] = {} - end - local value, err = datastore:get(key) - if not value then - return nil, err - end - result[server][subvar] = value end end end @@ -205,23 +171,25 @@ end utils.get_integration = function() -- Check if already in datastore - local integration, err = datastore:get("misc_integration") + local integration, err = datastore:get("misc_integration", true) if integration then return integration end + local variables, err = datastore:get("variables", true) + if not variables then + logger:log(ngx.ERR, "can't get variables from datastore : " .. err) + return "unknown" + end -- Swarm - local var, err = datastore:get("variable_SWARM_MODE") - if var == "yes" then + if variables["global"]["SWARM_MODE"] == "yes" then integration = "swarm" else -- Kubernetes - local var, err = datastore:get("variable_KUBERNETES_MODE") - if var == "yes" then + if variables["global"]["KUBERNETES_MODE"] == "yes" then integration = "kubernetes" else -- Autoconf - local var, err = datastore:get("variable_AUTOCONF_MODE") - if var == "yes" then + if variables["global"]["AUTOCONF_MODE"] == "yes" then integration = "autoconf" else -- Already present (e.g. : linux) @@ -247,7 +215,7 @@ utils.get_integration = function() end end -- Save integration - local ok, err = datastore:set("misc_integration", integration) + local ok, err = datastore:set("misc_integration", integration, nil, true) if not ok then logger:log(ngx.ERR, "can't cache integration to datastore : " .. err) end @@ -256,7 +224,7 @@ end utils.get_version = function() -- Check if already in datastore - local version, err = datastore:get("misc_version") + local version, err = datastore:get("misc_version", true) if version then return version end @@ -269,17 +237,17 @@ utils.get_version = function() version = f:read("*a"):gsub("[\n\r]", "") f:close() -- Save it to datastore - local ok, err = datastore:set("misc_version", version) + local ok, err = datastore:set("misc_version", version, nil, true) if not ok then logger:log(ngx.ERR, "can't cache version to datastore : " .. err) end return version end -utils.get_reason = function() +utils.get_reason = function(ctx) -- ngx.ctx - if ngx.ctx.reason then - return ngx.ctx.reason + if ctx.bw.reason then + return ctx.bw.reason end -- ngx.var if ngx.var.reason and ngx.var.reason ~= "" then @@ -295,7 +263,7 @@ utils.get_reason = function() return banned end -- unknown - if ngx.status == utils.get_deny_status() then + if ngx.status == utils.get_deny_status(ctx) then return "unknown" end return nil @@ -303,30 +271,30 @@ end utils.get_resolvers = function() -- Get resolvers from datastore if existing - local str_resolvers, err = datastore:get("misc_resolvers") - if str_resolvers then - return cjson.decode(str_resolvers) + local resolvers, err = datastore:get("misc_resolvers", true) + if resolvers then + return resolvers end -- Otherwise extract DNS_RESOLVERS variable - local var_resolvers, err = datastore:get("variable_DNS_RESOLVERS") - if not var_resolvers then - logger:log(ngx.ERR, "can't get variable DNS_RESOLVERS from datastore : " .. err) - return nil, err + local variables, err = datastore:get("variables", true) + if not variables then + logger:log(ngx.ERR, "can't get variables from datastore : " .. err) + return "unknown" end -- Make table for resolver1 resolver2 ... string local resolvers = {} - for str_resolver in var_resolvers:gmatch("%S+") do + for str_resolver in variables["global"]["DNS_RESOLVERS"]:gmatch("%S+") do table.insert(resolvers, str_resolver) end -- Add it to the datastore - local ok, err = datastore:set("misc_resolvers", cjson.encode(resolvers)) + local ok, err = datastore:set("misc_resolvers", resolvers, nil, true) if not ok then logger:log(ngx.ERR, "can't save misc_resolvers to datastore : " .. err) end return resolvers end -utils.get_rdns = function(ip) +utils.get_rdns = function(ip) -- Check cache local cachestore = utils.new_cachestore() local ok, value = cachestore:get("rdns_" .. ip) @@ -376,7 +344,7 @@ utils.get_rdns = function(ip) return ptrs, ret_err end -utils.get_ips = function(fqdn, ipv6) +utils.get_ips = function(fqdn, ipv6) -- Check cache local cachestore = utils.new_cachestore() local ok, value = cachestore:get("dns_" .. fqdn) @@ -497,38 +465,38 @@ utils.rand = function(nb, no_numbers) return result end -utils.get_deny_status = function() +utils.get_deny_status = function(ctx) -- Stream case - if ngx.ctx.bw and ngx.ctx.bw.kind == "stream" then + if ctx.bw and ctx.bw.kind == "stream" then return 444 end -- http case - local status, err = datastore:get("variable_DENY_HTTP_STATUS") - if not status then - logger:log(ngx.ERR, "can't get DENY_HTTP_STATUS variable " .. err) + local variables, err = datastore:get("variables", true) + if not variables then + logger:log(ngx.ERR, "can't get variables from datastore : " .. err) return 403 end - return tonumber(status) + return tonumber(variables["global"]["DENY_HTTP_STATUS"]) end -utils.check_session = function() - local _session, err, exists, refreshed = session.start({audience = "metadata"}) +utils.check_session = function(ctx) + local _session, err, exists, refreshed = session.start({ audience = "metadata" }) if exists then - for i, check in ipairs(ngx.ctx.bw.sessions_checks) do + for i, check in ipairs(ctx.bw.sessions_checks) do local key = check[1] local value = check[2] if _session:get(key) ~= value then + _session:clear_request_cookie() local ok, err = _session:destroy() if not ok then - _session:close() - return false, "session:destroy() error : " .. err + return false, "session:destroy() error : " .. err end logger:log(ngx.WARN, "session check " .. key .. " failed, destroying session") - return utils.check_session() + return utils.check_session(ctx) end end else - for i, check in ipairs(ngx.ctx.bw.sessions_checks) do + for i, check in ipairs(ctx.bw.sessions_checks) do _session:set(check[1], check[2]) end local ok, err = _session:save() @@ -537,41 +505,40 @@ utils.check_session = function() return false, "session:save() error : " .. err end end - ngx.ctx.bw.sessions_is_checked = true - _session:close() + ctx.bw.sessions_is_checked = true return true, exists end -utils.get_session = function(audience) +utils.get_session = function(audience, ctx) -- Check session - if not ngx.ctx.bw.sessions_is_checked then - local ok, err = utils.check_session() + if not ctx.bw.sessions_is_checked then + local ok, err = utils.check_session(ctx) if not ok then return false, "error while checking session, " .. err end end -- Open session with specific audience - local _session, err, exists = session.open({audience = audience}) + local _session, err, exists = session.open({ audience = audience }) if err then logger:log(ngx.INFO, "session:open() error : " .. err) end return _session end -utils.get_session_data = function(_session, site) +utils.get_session_data = function(_session, site, ctx) local site_only = site == nil or site local data = _session:get_data() if site_only then - return data[ngx.ctx.bw.server_name] or {} + return data[ctx.bw.server_name] or {} end return data end -utils.set_session_data = function(_session, data, site) +utils.set_session_data = function(_session, data, site, ctx) local site_only = site == nil or site if site_only then local all_data = _session:get_data() - all_data[ngx.ctx.bw.server_name] = data + all_data[ctx.bw.server_name] = data _session:set_data(all_data) return _session:save() end @@ -683,7 +650,7 @@ utils.new_cachestore = function() return require "bunkerweb.cachestore":new(use_redis, true) end -utils.regex_match = function(str, regex, options) +utils.regex_match = function(str, regex, options) local all_options = "o" if options then all_options = all_options .. options @@ -696,7 +663,7 @@ utils.regex_match = function(str, regex, options) return match end -utils.get_phases = function() +utils.get_phases = function() return { "init", "init_worker", @@ -710,7 +677,7 @@ utils.get_phases = function() } end -utils.is_cosocket_available = function() +utils.is_cosocket_available = function() local phases = { "timer", "access", @@ -725,7 +692,7 @@ utils.is_cosocket_available = function() return false end -utils.kill_all_threads = function(threads) +utils.kill_all_threads = function(threads) for i, thread in ipairs(threads) do local ok, err = ngx.thread.kill(thread) if not ok then @@ -734,7 +701,7 @@ utils.kill_all_threads = function(threads) end end -utils.get_ctx_obj = function(obj) +utils.get_ctx_obj = function(obj) if ngx.ctx and ngx.ctx.bw then return ngx.ctx.bw[obj] end diff --git a/src/bw/lua/middleclass.lua b/src/bw/lua/middleclass.lua index e4f9aa21b..0cafe197f 100644 --- a/src/bw/lua/middleclass.lua +++ b/src/bw/lua/middleclass.lua @@ -41,7 +41,7 @@ local function _createIndexWrapper(aClass, f) return (f(self, name)) end end - else -- if type(f) == "table" then + else -- if type(f) == "table" then return function(self, name) local value = aClass.__instanceDict[name] diff --git a/src/bw/misc/asn.mmdb b/src/bw/misc/asn.mmdb index 474a6a7b7..837f9f219 100644 Binary files a/src/bw/misc/asn.mmdb and b/src/bw/misc/asn.mmdb differ diff --git a/src/bw/misc/country.mmdb b/src/bw/misc/country.mmdb index 0bc884f92..8a76af1f6 100644 Binary files a/src/bw/misc/country.mmdb and b/src/bw/misc/country.mmdb differ diff --git a/src/common/api/API.py b/src/common/api/API.py index e300d9ac8..4a94f5474 100644 --- a/src/common/api/API.py +++ b/src/common/api/API.py @@ -1,52 +1,52 @@ +#!/usr/bin/python3 + +from typing import Literal, Optional, Union from requests import request class API: - def __init__(self, endpoint, host="bwapi"): + def __init__(self, endpoint: str, host: str = "bwapi"): self.__endpoint = endpoint + if not self.__endpoint.endswith("/"): + self.__endpoint += "/" self.__host = host - def get_endpoint(self): + @property + def endpoint(self) -> str: return self.__endpoint - def get_host(self): + @property + def host(self) -> str: return self.__host - def request(self, method, url, data=None, files=None, timeout=(10, 30)): + def request( + self, + method: Union[Literal["POST"], Literal["GET"]], + url: str, + data: Optional[Union[dict, bytes]] = None, + files=None, + timeout=(10, 30), + ) -> tuple[bool, str, Optional[int], Optional[dict]]: try: - headers = {} - headers["User-Agent"] = "bwapi" - headers["Host"] = self.__host + kwargs = {} if isinstance(data, dict): - resp = request( - method, - f"{self.__endpoint}{url}", - json=data, - timeout=timeout, - headers=headers, - ) + kwargs["json"] = data elif isinstance(data, bytes): - resp = request( - method, - f"{self.__endpoint}{url}", - data=data, - timeout=timeout, - headers=headers, - ) - elif files: - resp = request( - method, - f"{self.__endpoint}{url}", - files=files, - timeout=timeout, - headers=headers, - ) - elif not data: - resp = request( - method, f"{self.__endpoint}{url}", timeout=timeout, headers=headers - ) - else: - return False, "unsupported data type", None, None + kwargs["data"] = data + elif data is not None: + return False, f"Unsupported data type: {type(data)}", None, None + + if files: + kwargs["files"] = files + + resp = request( + method, + f"{self.__endpoint}{url if not url.startswith('/') else url[1:]}", + timeout=timeout, + headers={"User-Agent": "bwapi", "Host": self.__host}, + **kwargs, + ) except Exception as e: - return False, str(e), None, None + return False, f"Request failed: {e}", None, None + return True, "ok", resp.status_code, resp.json() diff --git a/src/common/cli/CLI.py b/src/common/cli/CLI.py index ba495ba11..60cd44fb9 100644 --- a/src/common/cli/CLI.py +++ b/src/common/cli/CLI.py @@ -1,17 +1,20 @@ -from os import getenv +#!/usr/bin/python3 + from dotenv import dotenv_values +from os import getenv, sep +from os.path import join from pathlib import Path from redis import StrictRedis from sys import path as sys_path from typing import Tuple -if "/usr/share/bunkerweb/utils" not in sys_path: - sys_path.append("/usr/share/bunkerweb/utils") +if join(sep, "usr", "share", "bunkerweb", "utils") not in sys_path: + sys_path.append(join(sep, "usr", "share", "bunkerweb", "utils")) -from API import API -from ApiCaller import ApiCaller -from logger import setup_logger +from API import API # type: ignore +from ApiCaller import ApiCaller # type: ignore +from logger import setup_logger # type: ignore def format_remaining_time(seconds): @@ -37,14 +40,15 @@ def format_remaining_time(seconds): class CLI(ApiCaller): def __init__(self): self.__logger = setup_logger("CLI", getenv("LOG_LEVEL", "INFO")) + db_path = Path(sep, "usr", "share", "bunkerweb", "db") - if not Path("/usr/share/bunkerweb/db").is_dir(): - self.__variables = dotenv_values("/etc/nginx/variables.env") + if not db_path.is_dir(): + self.__variables = dotenv_values(join(sep, "etc", "nginx", "variables.env")) else: - if "/usr/share/bunkerweb/db" not in sys_path: - sys_path.append("/usr/share/bunkerweb/db") + if str(db_path) not in sys_path: + sys_path.append(str(db_path)) - from Database import Database + from Database import Database # type: ignore db = Database( self.__logger, @@ -110,14 +114,14 @@ class CLI(ApiCaller): ) self.__use_redis = False - if not Path("/usr/share/bunkerweb/db").is_dir() or self.__integration not in ( + if not db_path.is_dir() or self.__integration not in ( "kubernetes", "swarm", "autoconf", ): # Docker & Linux case super().__init__( - apis=[ + [ API( f"http://127.0.0.1:{self.__variables.get('API_HTTP_PORT', '5000')}", host=self.__variables.get("API_SERVER_NAME", "bwapi"), @@ -129,17 +133,18 @@ class CLI(ApiCaller): self.auto_setup(self.__integration) def __detect_integration(self) -> str: + integration_path = Path(sep, "usr", "share", "bunkerweb", "INTEGRATION") + os_release_path = Path(sep, "etc", "os-release") if self.__variables.get("KUBERNETES_MODE", "no").lower() == "yes": return "kubernetes" elif self.__variables.get("SWARM_MODE", "no").lower() == "yes": return "swarm" elif self.__variables.get("AUTOCONF_MODE", "no").lower() == "yes": return "autoconf" - elif Path("/usr/share/bunkerweb/INTEGRATION").is_file(): - return Path("/usr/share/bunkerweb/INTEGRATION").read_text().strip().lower() - elif ( - Path("/etc/os-release").is_file() - and "Alpine" in Path("/etc/os-release").read_text() + elif integration_path.is_file(): + return integration_path.read_text(encoding="utf-8").strip().lower() + elif os_release_path.is_file() and "Alpine" in os_release_path.read_text( + encoding="utf-8" ): return "docker" @@ -151,7 +156,7 @@ class CLI(ApiCaller): if not ok: self.__logger.error(f"Failed to delete ban for {ip} from redis") - if self._send_to_apis("POST", "/unban", data={"ip": ip}): + if self.send_to_apis("POST", "/unban", data={"ip": ip}): return True, f"IP {ip} has been unbanned" return False, "error" @@ -165,7 +170,7 @@ class CLI(ApiCaller): if not ok: self.__logger.error(f"Failed to ban {ip} in redis") - if self._send_to_apis("POST", "/ban", data={"ip": ip, "exp": exp}): + if self.send_to_apis("POST", "/ban", data={"ip": ip, "exp": exp}): return ( True, f"IP {ip} has been banned for {format_remaining_time(exp)}", @@ -175,7 +180,7 @@ class CLI(ApiCaller): def bans(self) -> Tuple[bool, str]: servers = {} - ret, resp = self._send_to_apis("GET", "/bans", response=True) + ret, resp = self.send_to_apis("GET", "/bans", response=True) if not ret: return False, "error" @@ -203,7 +208,6 @@ class CLI(ApiCaller): for ban in bans: cli_str += f"- {ban['ip']} for {format_remaining_time(ban['exp'])} : {ban.get('reason', 'no reason given')}\n" - else: - cli_str += "\n" + cli_str += "\n" return True, cli_str diff --git a/src/common/cli/main.py b/src/common/cli/main.py index 15d2642b0..fe61834b2 100644 --- a/src/common/cli/main.py +++ b/src/common/cli/main.py @@ -1,20 +1,19 @@ -#!/usr/bin/env python3 +#!/usr/bin/python3 from argparse import ArgumentParser -from os import _exit, getenv -from sys import exit as sys_exit, path +from os import _exit, getenv, sep +from os.path import join +from sys import exit as sys_exit, path as sys_path from traceback import format_exc -path.extend( - ( - "/usr/share/bunkerweb/deps/python", - "/usr/share/bunkerweb/cli", - "/usr/share/bunkerweb/utils", - "/usr/share/bunkerweb/api", - ) -) +for deps_path in [ + join(sep, "usr", "share", "bunkerweb", *paths) + for paths in (("deps", "python"), ("utils",), ("api",), ("db",)) +]: + if deps_path not in sys_path: + sys_path.append(deps_path) -from logger import setup_logger +from logger import setup_logger # type: ignore from CLI import CLI if __name__ == "__main__": diff --git a/src/common/confs/api.conf b/src/common/confs/api.conf index 86958850b..8ee335650 100644 --- a/src/common/confs/api.conf +++ b/src/common/confs/api.conf @@ -5,7 +5,7 @@ server { listen {{ API_LISTEN_IP }}:{{ API_HTTP_PORT }}; {% if API_LISTEN_IP != "127.0.0.1" +%} listen 127.0.0.1:{{ API_HTTP_PORT }}; -{% endif +%} +{% endif %} # maximum body size for API client_max_body_size 1G; @@ -25,7 +25,7 @@ server { -- Fill ctx logger:log(ngx.INFO, "filling ngx.ctx ...") - local ok, ret, errors = helpers.fill_ctx() + local ok, ret, errors, ctx = helpers.fill_ctx() if not ok then logger:log(ngx.ERR, "fill_ctx() failed : " .. ret) elseif errors then @@ -36,30 +36,33 @@ server { logger:log(ngx.INFO, "ngx.ctx filled (ret = " .. ret .. ")") -- Check host header - if not ngx.ctx.bw.http_host or ngx.ctx.bw.http_host ~= "{{ API_SERVER_NAME }}" then - logger:log(ngx.WARN, "wrong Host header from IP " .. ngx.ctx.bw.remote_addr) + if not ctx.bw.http_host or ctx.bw.http_host ~= "{{ API_SERVER_NAME }}" then + logger:log(ngx.WARN, "wrong Host header from IP " .. ctx.bw.remote_addr) return ngx.exit(ngx.HTTP_CLOSE) end -- Check IP local ok, err = api:is_allowed_ip() if not ok then - logger:log(ngx.WARN, "can't validate access from IP " .. ngx.ctx.bw.remote_addr .. " : " .. err) + logger:log(ngx.WARN, "can't validate access from IP " .. ctx.bw.remote_addr .. " : " .. err) return ngx.exit(ngx.HTTP_CLOSE) end - logger:log(ngx.NOTICE, "validated access from IP " .. ngx.ctx.bw.remote_addr) + logger:log(ngx.NOTICE, "validated access from IP " .. ctx.bw.remote_addr) -- Do API call local ok, err, status, resp = api:do_api_call() if not ok then - logger:log(ngx.WARN, "call from " .. ngx.ctx.bw.remote_addr .. " on " .. ngx.ctx.bw.uri .. " failed : " .. err) + logger:log(ngx.WARN, "call from " .. ctx.bw.remote_addr .. " on " .. ctx.bw.uri .. " failed : " .. err) else - logger:log(ngx.NOTICE, "successful call from " .. ngx.ctx.bw.remote_addr .. " on " .. ngx.ctx.bw.uri .. " : " .. err) + logger:log(ngx.NOTICE, "successful call from " .. ctx.bw.remote_addr .. " on " .. ctx.bw.uri .. " : " .. err) end -- Start API handler logger:log(ngx.INFO, "API handler ended") + -- Save ctx + ngx.ctx = ctx + -- Send response ngx.status = status ngx.say(resp) diff --git a/src/common/confs/default-server-http.conf b/src/common/confs/default-server-http.conf index e6f600c46..a0b702adc 100644 --- a/src/common/confs/default-server-http.conf +++ b/src/common/confs/default-server-http.conf @@ -52,7 +52,7 @@ server { -- Fill ctx logger:log(ngx.INFO, "filling ngx.ctx ...") - local ok, ret, errors = helpers.fill_ctx() + local ok, ret, errors, ctx = helpers.fill_ctx() if not ok then logger:log(ngx.ERR, "fill_ctx() failed : " .. ret) elseif errors then @@ -63,12 +63,11 @@ server { logger:log(ngx.INFO, "ngx.ctx filled (ret = " .. ret .. ")") -- Get plugins order - local order, err = datastore:get("plugins_order") + local order, err = datastore:get("plugins_order", true) if not order then logger:log(ngx.ERR, "can't get plugins order from datastore : " .. err) return end - order = cjson.decode(order) -- Call log_default() methods logger:log(ngx.INFO, "calling log_default() methods of plugins ...") @@ -102,10 +101,13 @@ server { logger:log(ngx.INFO, "called log_default() methods of plugins") -- Display reason at info level - if ngx.ctx.reason then + if ctx.reason then logger:log(ngx.INFO, "client was denied with reason : " .. reason) end + -- Save ctx + ngx.ctx = ctx + logger:log(ngx.INFO, "log_default phase ended") } diff --git a/src/common/confs/http.conf b/src/common/confs/http.conf index 8494be3bb..6eef32804 100644 --- a/src/common/confs/http.conf +++ b/src/common/confs/http.conf @@ -15,7 +15,7 @@ default_type application/octet-stream; # access log format log_format logf '{{ LOG_FORMAT }}'; -access_log /var/log/nginx/access.log logf; +access_log /var/log/bunkerweb/access.log logf; # temp paths proxy_temp_path /var/tmp/bunkerweb/proxy_temp; @@ -53,6 +53,7 @@ lua_shared_dict cachestore_locks {{ CACHESTORE_LOCKS_MEMORY_SIZE }}; {% if LOG_LEVEL != "info" and LOG_LEVEL != "debug" %} lua_socket_log_errors off; {% endif %} +access_by_lua_no_postpone on; # LUA init block include /etc/nginx/init-lua.conf; diff --git a/src/common/confs/init-lua.conf b/src/common/confs/init-lua.conf index 66831f70c..bdcd80529 100644 --- a/src/common/confs/init-lua.conf +++ b/src/common/confs/init-lua.conf @@ -1,157 +1,136 @@ init_by_lua_block { + local class = require "middleclass" + local clogger = require "bunkerweb.logger" + local helpers = require "bunkerweb.helpers" + local cdatastore = require "bunkerweb.datastore" + local cjson = require "cjson" -local class = require "middleclass" -local clogger = require "bunkerweb.logger" -local helpers = require "bunkerweb.helpers" -local cdatastore = require "bunkerweb.datastore" -local cjson = require "cjson" + -- Start init phase + local logger = clogger:new("INIT") + local datastore = cdatastore:new() + logger:log(ngx.NOTICE, "init phase started") --- Start init phase -local logger = clogger:new("INIT") -local datastore = cdatastore:new() -logger:log(ngx.NOTICE, "init phase started") - --- Remove previous data from the datastore -logger:log(ngx.NOTICE, "deleting old keys from datastore ...") -local data_keys = {"^plugin", "^variable_", "^api_", "^misc_"} -for i, key in pairs(data_keys) do - local ok, err = datastore:delete_all(key) - if not ok then - logger:log(ngx.ERR, "can't delete " .. key .. " from datastore : " .. err) - return false - end - logger:log(ngx.INFO, "deleted " .. key .. " from datastore") -end -logger:log(ngx.NOTICE, "deleted old keys from datastore") - --- Load variables into the datastore -logger:log(ngx.NOTICE, "saving variables into datastore ...") -local file = io.open("/etc/nginx/variables.env") -if not file then - logger:log(ngx.ERR, "can't open /etc/nginx/variables.env file") - return false -end -file:close() -for line in io.lines("/etc/nginx/variables.env") do - local variable, value = line:match("^([^=]+)=(.*)$") - local ok, err = datastore:set("variable_" .. variable, value) - if not ok then - logger:log(ngx.ERR, "can't save variable " .. variable .. " into datastore : " .. err) - return false - end - logger:log(ngx.INFO, "saved variable " .. variable .. "=" .. value .. " into datastore") -end -logger:log(ngx.NOTICE, "saved variables into datastore") - --- Purge cache -local cachestore = require "bunkerweb.cachestore":new(false, true) -local ok, err = cachestore:purge() -if not ok then - logger:log(ngx.ERR, "can't purge cachestore : " .. err) -end - --- Set API values into the datastore -logger:log(ngx.NOTICE, "saving API values into datastore ...") -local value, err = datastore:get("variable_USE_API") -if not value then - logger:log(ngx.ERR, "can't get variable USE_API from the datastore : " .. err) - return false -end -if value == "yes" then - local value, err = datastore:get("variable_API_WHITELIST_IP") - if not value then - logger:log(ngx.ERR, "can't get variable API_WHITELIST_IP from the datastore : " .. err) - return false - end - local whitelists = {} - for whitelist in value:gmatch("%S+") do - table.insert(whitelists, whitelist) - end - local ok, err = datastore:set("api_whitelist_ip", cjson.encode(whitelists)) - if not ok then - logger:log(ngx.ERR, "can't save API whitelist_ip to datastore : " .. err) - return false - end - logger:log(ngx.INFO, "saved API whitelist_ip into datastore") -end -logger:log(ngx.NOTICE, "saved API values into datastore") - --- Load plugins into the datastore -logger:log(ngx.NOTICE, "saving plugins into datastore ...") -local plugins = {} -local plugin_paths = {"/usr/share/bunkerweb/core", "/etc/bunkerweb/plugins"} -for i, plugin_path in ipairs(plugin_paths) do - local paths = io.popen("find -L " .. plugin_path .. " -maxdepth 1 -type d ! -path " .. plugin_path) - for path in paths:lines() do - local ok, plugin = helpers.load_plugin(path .. "/plugin.json") + -- Remove previous data from the datastore + logger:log(ngx.NOTICE, "deleting old keys from datastore ...") + datastore:flush_lru() + local data_keys = { "^plugin", "^misc_" } + for i, key in pairs(data_keys) do + local ok, err = datastore:delete_all(key) if not ok then - logger:log(ngx.ERR, plugin) - else - local ok, err = datastore:set("plugin_" .. plugin.id, cjson.encode(plugin)) - if not ok then - logger:log(ngx.ERR, "can't save " .. plugin.id .. " into datastore : " .. err) - else - table.insert(plugins, plugin) - logger:log(ngx.NOTICE, "loaded plugin " .. plugin.id .. " v" .. plugin.version) - end + logger:log(ngx.ERR, "can't delete " .. key .. " from datastore : " .. err) + return false end + logger:log(ngx.INFO, "deleted " .. key .. " from datastore") end -end -local ok, err = datastore:set("plugins", cjson.encode(plugins)) -if not ok then - logger:log(ngx.ERR, "can't save plugins into datastore : " .. err) - return false -end + logger:log(ngx.NOTICE, "deleted old keys from datastore") -logger:log(ngx.NOTICE, "saving plugins order into datastore ...") -local ok, order = helpers.order_plugins(plugins) -if not ok then - logger:log(ngx.ERR, "can't compute plugins order : " .. err) - return false -end -for phase, id_list in pairs(order) do - logger:log(ngx.NOTICE, "plugins order for phase " .. phase .. " : " .. cjson.encode(id_list)) -end -local ok, err = datastore:set("plugins_order", cjson.encode(order)) -if not ok then - logger:log(ngx.ERR, "can't save plugins order into datastore : " .. err) - return false -end -logger:log(ngx.NOTICE, "saved plugins order into datastore") - --- Call init() method -logger:log(ngx.NOTICE, "calling init() methods of plugins ...") -for i, plugin_id in ipairs(order["init"]) do - -- Require call - local plugin_lua, err = helpers.require_plugin(plugin_id) - if plugin_lua == false then - logger:log(ngx.ERR, err) - elseif plugin_lua == nil then - logger:log(ngx.NOTICE, err) - else - -- Check if plugin has init method - if plugin_lua.init ~= nil then - -- New call - local ok, plugin_obj = helpers.new_plugin(plugin_lua) + -- Load plugins into the datastore + logger:log(ngx.NOTICE, "saving plugins into datastore ...") + local plugins = {} + local plugin_paths = { "/usr/share/bunkerweb/core", "/etc/bunkerweb/plugins" } + for i, plugin_path in ipairs(plugin_paths) do + local paths = io.popen("find -L " .. plugin_path .. " -maxdepth 1 -type d ! -path " .. plugin_path) + for path in paths:lines() do + local ok, plugin = helpers.load_plugin(path .. "/plugin.json") if not ok then - logger:log(ngx.ERR, plugin_obj) + logger:log(ngx.ERR, plugin) else - local ok, ret = helpers.call_plugin(plugin_obj, "init") + local ok, err = datastore:set("plugin_" .. plugin.id, plugin, nil, true) if not ok then - logger:log(ngx.ERR, ret) - elseif not ret.ret then - logger:log(ngx.ERR, plugin_id .. ":init() call failed : " .. ret.msg) + logger:log(ngx.ERR, "can't save " .. plugin.id .. " into datastore : " .. err) else - logger:log(ngx.NOTICE, plugin_id .. ":init() call successful : " .. ret.msg) + table.insert(plugins, plugin) + logger:log(ngx.NOTICE, "loaded plugin " .. plugin.id .. " v" .. plugin.version) end end - else - logger:log(ngx.NOTICE, "skipped execution of " .. plugin.id .. " because method init() is not defined") end end -end -logger:log(ngx.NOTICE, "called init() methods of plugins") + local ok, err = datastore:set("plugins", plugins, nil, true) + if not ok then + logger:log(ngx.ERR, "can't save plugins into datastore : " .. err) + return false + end -logger:log(ngx.NOTICE, "init phase ended") + -- Load variables into the datastore + logger:log(ngx.NOTICE, "saving variables into datastore ...") + local file = io.open("/etc/nginx/variables.env") + if not file then + logger:log(ngx.ERR, "can't open /etc/nginx/variables.env file") + return false + end + file:close() + local all_variables = {} + for line in io.lines("/etc/nginx/variables.env") do + local variable, value = line:match("^([^=]+)=(.*)$") + all_variables[variable] = value + end + local ok, variables = helpers.load_variables(all_variables, plugins) + if not ok then + logger:log(ngx.ERR, "error while loading variables : " .. variables) + return false + end + local ok, err = datastore:set("variables", variables, nil, true) + if not ok then + logger:log(ngx.ERR, "can't save plugins into datastore : " .. err) + return false + end + logger:log(ngx.NOTICE, "saved variables into datastore") + -- Purge cache + local cachestore = require "bunkerweb.cachestore":new(false, true) + local ok, err = cachestore:purge() + if not ok then + logger:log(ngx.ERR, "can't purge cachestore : " .. err) + end + + logger:log(ngx.NOTICE, "saving plugins order into datastore ...") + local ok, order = helpers.order_plugins(plugins) + if not ok then + logger:log(ngx.ERR, "can't compute plugins order : " .. err) + return false + end + for phase, id_list in pairs(order) do + logger:log(ngx.NOTICE, "plugins order for phase " .. phase .. " : " .. cjson.encode(id_list)) + end + local ok, err = datastore:set("plugins_order", order, nil, true) + if not ok then + logger:log(ngx.ERR, "can't save plugins order into datastore : " .. err) + return false + end + logger:log(ngx.NOTICE, "saved plugins order into datastore") + + -- Call init() method + logger:log(ngx.NOTICE, "calling init() methods of plugins ...") + for i, plugin_id in ipairs(order["init"]) do + -- Require call + local plugin_lua, err = helpers.require_plugin(plugin_id) + if plugin_lua == false then + logger:log(ngx.ERR, err) + elseif plugin_lua == nil then + logger:log(ngx.NOTICE, err) + else + -- Check if plugin has init method + if plugin_lua.init ~= nil then + -- New call + local ok, plugin_obj = helpers.new_plugin(plugin_lua) + if not ok then + logger:log(ngx.ERR, plugin_obj) + else + local ok, ret = helpers.call_plugin(plugin_obj, "init") + if not ok then + logger:log(ngx.ERR, ret) + elseif not ret.ret then + logger:log(ngx.ERR, plugin_id .. ":init() call failed : " .. ret.msg) + else + logger:log(ngx.NOTICE, plugin_id .. ":init() call successful : " .. ret.msg) + end + end + else + logger:log(ngx.NOTICE, "skipped execution of " .. plugin.id .. " because method init() is not defined") + end + end + end + logger:log(ngx.NOTICE, "called init() methods of plugins") + + logger:log(ngx.NOTICE, "init phase ended") } diff --git a/src/common/confs/init-stream-lua.conf b/src/common/confs/init-stream-lua.conf index 3b994be18..3598f5bb1 100644 --- a/src/common/confs/init-stream-lua.conf +++ b/src/common/confs/init-stream-lua.conf @@ -1,157 +1,136 @@ init_by_lua_block { + local class = require "middleclass" + local clogger = require "bunkerweb.logger" + local helpers = require "bunkerweb.helpers" + local cdatastore = require "bunkerweb.datastore" + local cjson = require "cjson" -local class = require "middleclass" -local clogger = require "bunkerweb.logger" -local helpers = require "bunkerweb.helpers" -local cdatastore = require "bunkerweb.datastore" -local cjson = require "cjson" + -- Start init phase + local logger = clogger:new("INIT") + local datastore = cdatastore:new() + logger:log(ngx.NOTICE, "init-stream phase started") --- Start init phase -local logger = clogger:new("INIT") -local datastore = cdatastore:new() -logger:log(ngx.NOTICE, "init-stream phase started") - --- Remove previous data from the datastore -logger:log(ngx.NOTICE, "deleting old keys from datastore ...") -local data_keys = {"^plugin", "^variable_", "^api_", "^misc_"} -for i, key in pairs(data_keys) do - local ok, err = datastore:delete_all(key) - if not ok then - logger:log(ngx.ERR, "can't delete " .. key .. " from datastore : " .. err) - return false - end - logger:log(ngx.INFO, "deleted " .. key .. " from datastore") -end -logger:log(ngx.NOTICE, "deleted old keys from datastore") - --- Load variables into the datastore -logger:log(ngx.NOTICE, "saving variables into datastore ...") -local file = io.open("/etc/nginx/variables.env") -if not file then - logger:log(ngx.ERR, "can't open /etc/nginx/variables.env file") - return false -end -file:close() -for line in io.lines("/etc/nginx/variables.env") do - local variable, value = line:match("^([^=]+)=(.*)$") - local ok, err = datastore:set("variable_" .. variable, value) - if not ok then - logger:log(ngx.ERR, "can't save variable " .. variable .. " into datastore : " .. err) - return false - end - logger:log(ngx.INFO, "saved variable " .. variable .. "=" .. value .. " into datastore") -end -logger:log(ngx.NOTICE, "saved variables into datastore") - --- Purge cache -local cachestore = require "bunkerweb.cachestore":new(false, true) -local ok, err = cachestore:purge() -if not ok then - logger:log(ngx.ERR, "can't purge cachestore : " .. err) -end - --- Set API values into the datastore -logger:log(ngx.NOTICE, "saving API values into datastore ...") -local value, err = datastore:get("variable_USE_API") -if not value then - logger:log(ngx.ERR, "can't get variable USE_API from the datastore : " .. err) - return false -end -if value == "yes" then - local value, err = datastore:get("variable_API_WHITELIST_IP") - if not value then - logger:log(ngx.ERR, "can't get variable API_WHITELIST_IP from the datastore : " .. err) - return false - end - local whitelists = {} - for whitelist in value:gmatch("%S+") do - table.insert(whitelists, whitelist) - end - local ok, err = datastore:set("api_whitelist_ip", cjson.encode(whitelists)) - if not ok then - logger:log(ngx.ERR, "can't save API whitelist_ip to datastore : " .. err) - return false - end - logger:log(ngx.INFO, "saved API whitelist_ip into datastore") -end -logger:log(ngx.NOTICE, "saved API values into datastore") - --- Load plugins into the datastore -logger:log(ngx.NOTICE, "saving plugins into datastore ...") -local plugins = {} -local plugin_paths = {"/usr/share/bunkerweb/core", "/etc/bunkerweb/plugins"} -for i, plugin_path in ipairs(plugin_paths) do - local paths = io.popen("find -L " .. plugin_path .. " -maxdepth 1 -type d ! -path " .. plugin_path) - for path in paths:lines() do - local ok, plugin = helpers.load_plugin(path .. "/plugin.json") + -- Remove previous data from the datastore + logger:log(ngx.NOTICE, "deleting old keys from datastore ...") + datastore:flush_lru() + local data_keys = { "^plugin", "^misc_" } + for i, key in pairs(data_keys) do + local ok, err = datastore:delete_all(key) if not ok then - logger:log(ngx.ERR, plugin) - else - local ok, err = datastore:set("plugin_" .. plugin.id, cjson.encode(plugin)) - if not ok then - logger:log(ngx.ERR, "can't save " .. plugin.id .. " into datastore : " .. err) - else - table.insert(plugins, plugin) - logger:log(ngx.NOTICE, "loaded plugin " .. plugin.id .. " v" .. plugin.version) - end + logger:log(ngx.ERR, "can't delete " .. key .. " from datastore : " .. err) + return false end + logger:log(ngx.INFO, "deleted " .. key .. " from datastore") end -end -local ok, err = datastore:set("plugins", cjson.encode(plugins)) -if not ok then - logger:log(ngx.ERR, "can't save plugins into datastore : " .. err) - return false -end + logger:log(ngx.NOTICE, "deleted old keys from datastore") -logger:log(ngx.NOTICE, "saving plugins order into datastore ...") -local ok, order = helpers.order_plugins(plugins) -if not ok then - logger:log(ngx.ERR, "can't compute plugins order : " .. err) - return false -end -for phase, id_list in pairs(order) do - logger:log(ngx.NOTICE, "plugins order for phase " .. phase .. " : " .. cjson.encode(id_list)) -end -local ok, err = datastore:set("plugins_order", cjson.encode(order)) -if not ok then - logger:log(ngx.ERR, "can't save plugins order into datastore : " .. err) - return false -end -logger:log(ngx.NOTICE, "saved plugins order into datastore") - --- Call init() method -logger:log(ngx.NOTICE, "calling init() methods of plugins ...") -for i, plugin_id in ipairs(order["init"]) do - -- Require call - local plugin_lua, err = helpers.require_plugin(plugin_id) - if plugin_lua == false then - logger:log(ngx.ERR, err) - elseif plugin_lua == nil then - logger:log(ngx.NOTICE, err) - else - -- Check if plugin has init method - if plugin_lua.init ~= nil then - -- New call - local ok, plugin_obj = helpers.new_plugin(plugin_lua) + -- Load plugins into the datastore + logger:log(ngx.NOTICE, "saving plugins into datastore ...") + local plugins = {} + local plugin_paths = { "/usr/share/bunkerweb/core", "/etc/bunkerweb/plugins" } + for i, plugin_path in ipairs(plugin_paths) do + local paths = io.popen("find -L " .. plugin_path .. " -maxdepth 1 -type d ! -path " .. plugin_path) + for path in paths:lines() do + local ok, plugin = helpers.load_plugin(path .. "/plugin.json") if not ok then - logger:log(ngx.ERR, plugin_obj) + logger:log(ngx.ERR, plugin) else - local ok, ret = helpers.call_plugin(plugin_obj, "init") + local ok, err = datastore:set("plugin_" .. plugin.id, plugin, true) if not ok then - logger:log(ngx.ERR, ret) - elseif not ret.ret then - logger:log(ngx.ERR, plugin_id .. ":init() call failed : " .. ret.msg) + logger:log(ngx.ERR, "can't save " .. plugin.id .. " into datastore : " .. err) else - logger:log(ngx.NOTICE, plugin_id .. ":init() call successful : " .. ret.msg) + table.insert(plugins, plugin) + logger:log(ngx.NOTICE, "loaded plugin " .. plugin.id .. " v" .. plugin.version) end end - else - logger:log(ngx.NOTICE, "skipped execution of " .. plugin.id .. " because method init() is not defined") end end -end -logger:log(ngx.NOTICE, "called init() methods of plugins") + local ok, err = datastore:set("plugins", plugins, nil, true) + if not ok then + logger:log(ngx.ERR, "can't save plugins into datastore : " .. err) + return false + end -logger:log(ngx.NOTICE, "init-stream phase ended") + -- Load variables into the datastore + logger:log(ngx.NOTICE, "saving variables into datastore ...") + local file = io.open("/etc/nginx/variables.env") + if not file then + logger:log(ngx.ERR, "can't open /etc/nginx/variables.env file") + return false + end + file:close() + local all_variables = {} + for line in io.lines("/etc/nginx/variables.env") do + local variable, value = line:match("^([^=]+)=(.*)$") + all_variables[variable] = value + end + local ok, variables = helpers.load_variables(all_variables, plugins) + if not ok then + logger:log(ngx.ERR, "error while loading variables : " .. variables) + return false + end + local ok, err = datastore:set("variables", variables, nil, true) + if not ok then + logger:log(ngx.ERR, "can't save plugins into datastore : " .. err) + return false + end + logger:log(ngx.NOTICE, "saved variables into datastore") + -- Purge cache + local cachestore = require "bunkerweb.cachestore":new(false, true) + local ok, err = cachestore:purge() + if not ok then + logger:log(ngx.ERR, "can't purge cachestore : " .. err) + end + + logger:log(ngx.NOTICE, "saving plugins order into datastore ...") + local ok, order = helpers.order_plugins(plugins) + if not ok then + logger:log(ngx.ERR, "can't compute plugins order : " .. err) + return false + end + for phase, id_list in pairs(order) do + logger:log(ngx.NOTICE, "plugins order for phase " .. phase .. " : " .. cjson.encode(id_list)) + end + local ok, err = datastore:set("plugins_order", order, nil, true) + if not ok then + logger:log(ngx.ERR, "can't save plugins order into datastore : " .. err) + return false + end + logger:log(ngx.NOTICE, "saved plugins order into datastore") + + -- Call init() method + logger:log(ngx.NOTICE, "calling init() methods of plugins ...") + for i, plugin_id in ipairs(order["init"]) do + -- Require call + local plugin_lua, err = helpers.require_plugin(plugin_id) + if plugin_lua == false then + logger:log(ngx.ERR, err) + elseif plugin_lua == nil then + logger:log(ngx.NOTICE, err) + else + -- Check if plugin has init method + if plugin_lua.init ~= nil then + -- New call + local ok, plugin_obj = helpers.new_plugin(plugin_lua) + if not ok then + logger:log(ngx.ERR, plugin_obj) + else + local ok, ret = helpers.call_plugin(plugin_obj, "init") + if not ok then + logger:log(ngx.ERR, ret) + elseif not ret.ret then + logger:log(ngx.ERR, plugin_id .. ":init() call failed : " .. ret.msg) + else + logger:log(ngx.NOTICE, plugin_id .. ":init() call successful : " .. ret.msg) + end + end + else + logger:log(ngx.NOTICE, "skipped execution of " .. plugin.id .. " because method init() is not defined") + end + end + end + logger:log(ngx.NOTICE, "called init() methods of plugins") + + logger:log(ngx.NOTICE, "init-stream phase ended") } diff --git a/src/common/confs/init-worker-lua.conf b/src/common/confs/init-worker-lua.conf index b7629f12c..f2a3edf86 100644 --- a/src/common/confs/init-worker-lua.conf +++ b/src/common/confs/init-worker-lua.conf @@ -1,121 +1,116 @@ lua_shared_dict worker_lock 16k; init_worker_by_lua_block { + -- Our timer function + local ready_work = function(premature) + -- Libs + local helpers = require "bunkerweb.helpers" + local cjson = require "cjson" --- Our timer function -local ready_work = function(premature) + -- Instantiate objects + local logger = require "bunkerweb.logger":new("INIT-WORKER") + local datastore = require "bunkerweb.datastore":new() - -- Libs - local helpers = require "bunkerweb.helpers" - local cjson = require "cjson" - - -- Instantiate objects - local logger = require "bunkerweb.logger":new("INIT-WORKER") - local datastore = require "bunkerweb.datastore":new() - - -- Don't go further we are in loading state - local is_loading, err = require "bunkerweb.utils".get_variable("IS_LOADING", false) - if not is_loading then - logger:log(ngx.ERR, "utils.get_variable() failed : " .. err) - return - elseif is_loading == "yes" then - return - end - - -- Instantiate lock - local lock = require "resty.lock":new("worker_lock", {timeout = 10}) - if not lock then - logger:log(ngx.ERR, "lock:new() failed : " .. err) - return - end - - -- Acquire lock - local elapsed, err = lock:lock("ready") - if elapsed == nil then - logger:log(ngx.ERR, "lock:lock() failed : " .. err) - return - end - - -- Check if work is done - local ok, err = datastore:get("misc_ready") - if not ok and err ~= "not found" then - logger:log(ngx.ERR, "datastore:get() failed : " .. err) - local ok, err = lock:unlock() - if not ok then - logger:log(ngx.ERR, "lock:unlock() failed : " .. err) + -- Don't go further we are in loading state + local is_loading, err = require "bunkerweb.utils".get_variable("IS_LOADING", false) + if not is_loading then + logger:log(ngx.ERR, "utils.get_variable() failed : " .. err) + return + elseif is_loading == "yes" then + return end - return - end - if ok then - local ok, err = lock:unlock() - if not ok then - logger:log(ngx.ERR, "lock:unlock() failed : " .. err) + + -- Instantiate lock + local lock = require "resty.lock":new("worker_lock", { timeout = 10 }) + if not lock then + logger:log(ngx.ERR, "lock:new() failed : " .. err) + return end - return - end - logger:log(ngx.INFO, "init_worker phase started") - - -- Get plugins order - local order, err = datastore:get("plugins_order") - if not order then - logger:log(ngx.ERR, "can't get plugins order from datastore : " .. err) - local ok, err = lock:unlock() - if not ok then - logger:log(ngx.ERR, "lock:unlock() failed : " .. err) + -- Acquire lock + local elapsed, err = lock:lock("ready") + if elapsed == nil then + logger:log(ngx.ERR, "lock:lock() failed : " .. err) + return end - return - end - order = cjson.decode(order) - -- Call init_worker() methods - logger:log(ngx.INFO, "calling init_worker() methods of plugins ...") - for i, plugin_id in ipairs(order.init_worker) do - -- Require call - local plugin_lua, err = helpers.require_plugin(plugin_id) - if plugin_lua == false then - logger:log(ngx.ERR, err) - elseif plugin_lua == nil then - logger:log(ngx.INFO, err) - else - -- Check if plugin has init_worker method - if plugin_lua.init_worker ~= nil then - -- New call - local ok, plugin_obj = helpers.new_plugin(plugin_lua) - if not ok then - logger:log(ngx.ERR, plugin_obj) - else - local ok, ret = helpers.call_plugin(plugin_obj, "init_worker") - if not ok then - logger:log(ngx.ERR, ret) - elseif not ret.ret then - logger:log(ngx.ERR, plugin_id .. ":init_worker() call failed : " .. ret.msg) - else - logger:log(ngx.INFO, plugin_id .. ":init_worker() call successful : " .. ret.msg) - end - end + -- Check if work is done + local ok, err = datastore:get("misc_ready") + if not ok and err ~= "not found" then + logger:log(ngx.ERR, "datastore:get() failed : " .. err) + local ok, err = lock:unlock() + if not ok then + logger:log(ngx.ERR, "lock:unlock() failed : " .. err) + end + return + end + if ok then + local ok, err = lock:unlock() + if not ok then + logger:log(ngx.ERR, "lock:unlock() failed : " .. err) + end + return + end + + logger:log(ngx.INFO, "init_worker phase started") + + -- Get plugins order + local order, err = datastore:get("plugins_order", true) + if not order then + logger:log(ngx.ERR, "can't get plugins order from datastore : " .. err) + local ok, err = lock:unlock() + if not ok then + logger:log(ngx.ERR, "lock:unlock() failed : " .. err) + end + return + end + + -- Call init_worker() methods + logger:log(ngx.INFO, "calling init_worker() methods of plugins ...") + for i, plugin_id in ipairs(order.init_worker) do + -- Require call + local plugin_lua, err = helpers.require_plugin(plugin_id) + if plugin_lua == false then + logger:log(ngx.ERR, err) + elseif plugin_lua == nil then + logger:log(ngx.INFO, err) else - logger:log(ngx.INFO, "skipped execution of " .. plugin_id .. " because method init_worker() is not defined") + -- Check if plugin has init_worker method + if plugin_lua.init_worker ~= nil then + -- New call + local ok, plugin_obj = helpers.new_plugin(plugin_lua) + if not ok then + logger:log(ngx.ERR, plugin_obj) + else + local ok, ret = helpers.call_plugin(plugin_obj, "init_worker") + if not ok then + logger:log(ngx.ERR, ret) + elseif not ret.ret then + logger:log(ngx.ERR, plugin_id .. ":init_worker() call failed : " .. ret.msg) + else + logger:log(ngx.INFO, plugin_id .. ":init_worker() call successful : " .. ret.msg) + end + end + else + logger:log(ngx.INFO, "skipped execution of " .. plugin_id .. " because method init_worker() is not defined") + end end end + logger:log(ngx.INFO, "called init_worker() methods of plugins") + + -- End + local ok, err = datastore:set("misc_ready", "ok") + if not ok then + logger:log(ngx.ERR, "datastore:set() failed : " .. err) + end + local ok, err = lock:unlock() + if not ok then + logger:log(ngx.ERR, "lock:unlock() failed : " .. err) + end + logger:log(ngx.INFO, "init phase ended") + logger:log(ngx.NOTICE, "BunkerWeb is ready to fool hackers ! 🚀") end - logger:log(ngx.INFO, "called init_worker() methods of plugins") - - -- End - local ok, err = datastore:set("misc_ready", "ok") - if not ok then - logger:log(ngx.ERR, "datastore:set() failed : " .. err) - end - local ok, err = lock:unlock() - if not ok then - logger:log(ngx.ERR, "lock:unlock() failed : " .. err) - end - logger:log(ngx.INFO, "init phase ended") - logger:log(ngx.NOTICE, "BunkerWeb is ready to fool hackers ! 🚀") - -end - --- Start timer -ngx.timer.at(5, ready_work) + -- Start timer + ngx.timer.at(5, ready_work) } diff --git a/src/common/confs/nginx.conf b/src/common/confs/nginx.conf index f284b030a..7bf691d5b 100644 --- a/src/common/confs/nginx.conf +++ b/src/common/confs/nginx.conf @@ -15,7 +15,7 @@ load_module /usr/share/bunkerweb/modules/ngx_http_brotli_static_module.so; load_module /usr/share/bunkerweb/modules/ngx_stream_lua_module.so; # PID file -pid /var/tmp/bunkerweb/nginx.pid; +pid /var/run/bunkerweb/nginx.pid; # worker number (default = auto) worker_processes {{ WORKER_PROCESSES }}; @@ -27,7 +27,7 @@ pcre_jit on; worker_rlimit_nofile {{ WORKER_RLIMIT_NOFILE }}; # error log level -error_log /var/log/nginx/error.log {{ LOG_LEVEL }}; +error_log /var/log/bunkerweb/error.log {{ LOG_LEVEL }}; # reason env var env REASON; diff --git a/src/common/confs/server-http/access-lua.conf b/src/common/confs/server-http/access-lua.conf index 945296bbf..8d6edc844 100644 --- a/src/common/confs/server-http/access-lua.conf +++ b/src/common/confs/server-http/access-lua.conf @@ -1,124 +1,119 @@ access_by_lua_block { + local class = require "middleclass" + local clogger = require "bunkerweb.logger" + local helpers = require "bunkerweb.helpers" + local utils = require "bunkerweb.utils" + local cdatastore = require "bunkerweb.datastore" + local cclusterstore = require "bunkerweb.clusterstore" + local cjson = require "cjson" -local class = require "middleclass" -local clogger = require "bunkerweb.logger" -local helpers = require "bunkerweb.helpers" -local utils = require "bunkerweb.utils" -local cdatastore = require "bunkerweb.datastore" -local cclusterstore = require "bunkerweb.clusterstore" -local cjson = require "cjson" - --- Don't process internal requests -local logger = clogger:new("ACCESS") -if ngx.req.is_internal() then - logger:log(ngx.INFO, "skipped access phase because request is internal") - return true -end - --- Start access phase -local datastore = cdatastore:new() -logger:log(ngx.INFO, "access phase started") - --- Fill ctx -logger:log(ngx.INFO, "filling ngx.ctx ...") -local ok, ret, errors = helpers.fill_ctx() -if not ok then - logger:log(ngx.ERR, "fill_ctx() failed : " .. ret) -elseif errors then - for i, error in ipairs(errors) do - logger:log(ngx.ERR, "fill_ctx() error " .. tostring(i) .. " : " .. error) + -- Don't process internal requests + local logger = clogger:new("ACCESS") + if ngx.req.is_internal() then + logger:log(ngx.INFO, "skipped access phase because request is internal") + return true end -end -logger:log(ngx.INFO, "ngx.ctx filled (ret = " .. ret .. ")") --- Process bans as soon as possible -local banned, reason, ttl = utils.is_banned(ngx.ctx.bw.remote_addr) -if banned == nil then - logger:log(ngx.ERR, "can't check if IP " .. ngx.ctx.bw.remote_addr .. " is banned : " .. reason) -elseif banned then - logger:log(ngx.WARN, "IP " .. ngx.ctx.bw.remote_addr .. " is banned with reason " .. reason .. " (" .. tostring(ttl) .. "s remaining)") - return ngx.exit(utils.get_deny_status()) -else - logger:log(ngx.INFO, "IP " .. ngx.ctx.bw.remote_addr .. " is not banned") -end + -- Start access phase + local datastore = cdatastore:new() + logger:log(ngx.INFO, "access phase started") --- Get plugins order -local order, err = datastore:get("plugins_order") -if not order then - logger:log(ngx.ERR, "can't get plugins order from datastore : " .. err) - return -end -order = cjson.decode(order) - --- Call access() methods -logger:log(ngx.INFO, "calling access() methods of plugins ...") -local status = nil -local redirect = nil -for i, plugin_id in ipairs(order.access) do - -- Require call - local plugin_lua, err = helpers.require_plugin(plugin_id) - if plugin_lua == false then - logger:log(ngx.ERR, err) - elseif plugin_lua == nil then - logger:log(ngx.INFO, err) - else - -- Check if plugin has access method - if plugin_lua.access ~= nil then - -- New call - local ok, plugin_obj = helpers.new_plugin(plugin_lua) - if not ok then - logger:log(ngx.ERR, plugin_obj) - else - local ok, ret = helpers.call_plugin(plugin_obj, "access") - if not ok then - logger:log(ngx.ERR, ret) - elseif not ret.ret then - logger:log(ngx.ERR, plugin_id .. ":access() call failed : " .. ret.msg) - else - logger:log(ngx.INFO, plugin_id .. ":access() call successful : " .. ret.msg) - end - if ret.status then - if ret.status == utils.get_deny_status() then - ngx.ctx.reason = plugin_id - logger:log(ngx.WARN, "denied access from " .. plugin_id .. " : " .. ret.msg) - else - logger:log(ngx.NOTICE, plugin_id .. " returned status " .. tostring(ret.status) .. " : " .. ret.msg) - end - status = ret.status - break - elseif ret.redirect then - logger:log(ngx.NOTICE, plugin_id .. " redirect to " .. ret.redirect .. " : " .. ret.msg) - redirect = ret.redirect - break - end - end - else - logger:log(ngx.INFO, "skipped execution of " .. plugin_id .. " because method access() is not defined") + -- Fill ctx + logger:log(ngx.INFO, "filling ngx.ctx ...") + local ok, ret, errors, ctx = helpers.fill_ctx() + if not ok then + logger:log(ngx.ERR, "fill_ctx() failed : " .. ret) + elseif errors then + for i, error in ipairs(errors) do + logger:log(ngx.ERR, "fill_ctx() error " .. tostring(i) .. " : " .. error) end end -end -logger:log(ngx.INFO, "called access() methods of plugins") + logger:log(ngx.INFO, "ngx.ctx filled (ret = " .. ret .. ")") --- Save session if needed --- local ok, err = utils.save_session() --- if not ok then --- logger:log(ngx.ERR, "can't save session : " .. err) --- else --- logger:log(ngx.INFO, "session save return : " .. err) --- end + -- Process bans as soon as possible + if ctx.bw.is_whitelisted ~= "yes" then + local banned, reason, ttl = utils.is_banned(ctx.bw.remote_addr) + if banned == nil then + logger:log(ngx.ERR, "can't check if IP " .. ctx.bw.remote_addr .. " is banned : " .. reason) + elseif banned then + logger:log(ngx.WARN, + "IP " .. ctx.bw.remote_addr .. " is banned with reason " .. reason .. " (" .. tostring(ttl) .. "s remaining)") + return ngx.exit(utils.get_deny_status(ctx)) + else + logger:log(ngx.INFO, "IP " .. ctx.bw.remote_addr .. " is not banned") + end + end -logger:log(ngx.INFO, "access phase ended") + -- Get plugins order + local order, err = datastore:get("plugins_order", true) + if not order then + logger:log(ngx.ERR, "can't get plugins order from datastore : " .. err) + return + end --- Return status if needed -if status then - return ngx.exit(status) -end + -- Call access() methods + logger:log(ngx.INFO, "calling access() methods of plugins ...") + local status = nil + local redirect = nil + for i, plugin_id in ipairs(order.access) do + -- Require call + local plugin_lua, err = helpers.require_plugin(plugin_id) + if plugin_lua == false then + logger:log(ngx.ERR, err) + elseif plugin_lua == nil then + logger:log(ngx.INFO, err) + else + -- Check if plugin has access method + if plugin_lua.access ~= nil then + -- New call + local ok, plugin_obj = helpers.new_plugin(plugin_lua, ctx) + if not ok then + logger:log(ngx.ERR, plugin_obj) + else + local ok, ret = helpers.call_plugin(plugin_obj, "access") + if not ok then + logger:log(ngx.ERR, ret) + elseif not ret.ret then + logger:log(ngx.ERR, plugin_id .. ":access() call failed : " .. ret.msg) + else + logger:log(ngx.INFO, plugin_id .. ":access() call successful : " .. ret.msg) + end + if ret.status then + if ret.status == utils.get_deny_status(ctx) then + ctx.bw.reason = plugin_id + logger:log(ngx.WARN, "denied access from " .. plugin_id .. " : " .. ret.msg) + else + logger:log(ngx.NOTICE, plugin_id .. " returned status " .. tostring(ret.status) .. " : " .. ret.msg) + end + status = ret.status + break + elseif ret.redirect then + logger:log(ngx.NOTICE, plugin_id .. " redirect to " .. ret.redirect .. " : " .. ret.msg) + redirect = ret.redirect + break + end + end + else + logger:log(ngx.INFO, "skipped execution of " .. plugin_id .. " because method access() is not defined") + end + end + end + logger:log(ngx.INFO, "called access() methods of plugins") --- Redirect if needed -if redirect then - return ngx.redirect(redirect) -end + -- Save ctx + ngx.ctx = ctx -return true + logger:log(ngx.INFO, "access phase ended") -} \ No newline at end of file + -- Return status if needed + if status then + return ngx.exit(status) + end + + -- Redirect if needed + if redirect then + return ngx.redirect(redirect) + end + + return true +} diff --git a/src/common/confs/server-http/header-lua.conf b/src/common/confs/server-http/header-lua.conf index a8bf6ff80..871f499fe 100644 --- a/src/common/confs/server-http/header-lua.conf +++ b/src/common/confs/server-http/header-lua.conf @@ -1,69 +1,69 @@ header_filter_by_lua_block { + local class = require "middleclass" + local clogger = require "bunkerweb.logger" + local helpers = require "bunkerweb.helpers" + local cdatastore = require "bunkerweb.datastore" + local cjson = require "cjson" -local class = require "middleclass" -local clogger = require "bunkerweb.logger" -local helpers = require "bunkerweb.helpers" -local cdatastore = require "bunkerweb.datastore" -local cjson = require "cjson" + -- Start set phase + local logger = clogger:new("HEADER") + local datastore = cdatastore:new() + logger:log(ngx.INFO, "header phase started") --- Start set phase -local logger = clogger:new("HEADER") -local datastore = cdatastore:new() -logger:log(ngx.INFO, "header phase started") - --- Fill ctx -logger:log(ngx.INFO, "filling ngx.ctx ...") -local ok, ret, errors = helpers.fill_ctx() -if not ok then - logger:log(ngx.ERR, "fill_ctx() failed : " .. ret) -elseif errors then - for i, error in ipairs(errors) do - logger:log(ngx.ERR, "fill_ctx() error " .. tostring(i) .. " : " .. error) - end -end -logger:log(ngx.INFO, "ngx.ctx filled (ret = " .. ret .. ")") - --- Get plugins order -local order, err = datastore:get("plugins_order") -if not order then - logger:log(ngx.ERR, "can't get plugins order from datastore : " .. err) - return -end -order = cjson.decode(order) - --- Call header() methods -logger:log(ngx.INFO, "calling header() methods of plugins ...") -for i, plugin_id in ipairs(order.header) do - -- Require call - local plugin_lua, err = helpers.require_plugin(plugin_id) - if plugin_lua == false then - logger:log(ngx.ERR, err) - elseif plugin_lua == nil then - logger:log(ngx.INFO, err) - else - -- Check if plugin has header method - if plugin_lua.header ~= nil then - -- New call - local ok, plugin_obj = helpers.new_plugin(plugin_lua) - if not ok then - logger:log(ngx.ERR, plugin_obj) - else - local ok, ret = helpers.call_plugin(plugin_obj, "header") - if not ok then - logger:log(ngx.ERR, ret) - elseif not ret.ret then - logger:log(ngx.ERR, plugin_id .. ":header() call failed : " .. ret.msg) - else - logger:log(ngx.INFO, plugin_id .. ":header() call successful : " .. ret.msg) - end - end - else - logger:log(ngx.INFO, "skipped execution of " .. plugin_id .. " because method header() is not defined") + -- Fill ctx + logger:log(ngx.INFO, "filling ngx.ctx ...") + local ok, ret, errors, ctx = helpers.fill_ctx() + if not ok then + logger:log(ngx.ERR, "fill_ctx() failed : " .. ret) + elseif errors then + for i, error in ipairs(errors) do + logger:log(ngx.ERR, "fill_ctx() error " .. tostring(i) .. " : " .. error) end end -end -logger:log(ngx.INFO, "called header() methods of plugins") + logger:log(ngx.INFO, "ngx.ctx filled (ret = " .. ret .. ")") -return true + -- Get plugins order + local order, err = datastore:get("plugins_order", true) + if not order then + logger:log(ngx.ERR, "can't get plugins order from datastore : " .. err) + return + end -} \ No newline at end of file + -- Call header() methods + logger:log(ngx.INFO, "calling header() methods of plugins ...") + for i, plugin_id in ipairs(order.header) do + -- Require call + local plugin_lua, err = helpers.require_plugin(plugin_id) + if plugin_lua == false then + logger:log(ngx.ERR, err) + elseif plugin_lua == nil then + logger:log(ngx.INFO, err) + else + -- Check if plugin has header method + if plugin_lua.header ~= nil then + -- New call + local ok, plugin_obj = helpers.new_plugin(plugin_lua, ctx) + if not ok then + logger:log(ngx.ERR, plugin_obj) + else + local ok, ret = helpers.call_plugin(plugin_obj, "header") + if not ok then + logger:log(ngx.ERR, ret) + elseif not ret.ret then + logger:log(ngx.ERR, plugin_id .. ":header() call failed : " .. ret.msg) + else + logger:log(ngx.INFO, plugin_id .. ":header() call successful : " .. ret.msg) + end + end + else + logger:log(ngx.INFO, "skipped execution of " .. plugin_id .. " because method header() is not defined") + end + end + end + logger:log(ngx.INFO, "called header() methods of plugins") + + -- Save ctx + ngx.ctx = ctx + + return true +} diff --git a/src/common/confs/server-http/log-lua.conf b/src/common/confs/server-http/log-lua.conf index bb169996c..29ec7d702 100644 --- a/src/common/confs/server-http/log-lua.conf +++ b/src/common/confs/server-http/log-lua.conf @@ -1,74 +1,74 @@ log_by_lua_block { + local class = require "middleclass" + local clogger = require "bunkerweb.logger" + local helpers = require "bunkerweb.helpers" + local cdatastore = require "bunkerweb.datastore" + local cjson = require "cjson" -local class = require "middleclass" -local clogger = require "bunkerweb.logger" -local helpers = require "bunkerweb.helpers" -local cdatastore = require "bunkerweb.datastore" -local cjson = require "cjson" + -- Start log phase + local logger = clogger:new("LOG") + local datastore = cdatastore:new() + logger:log(ngx.INFO, "log phase started") --- Start log phase -local logger = clogger:new("LOG") -local datastore = cdatastore:new() -logger:log(ngx.INFO, "log phase started") - --- Fill ctx -logger:log(ngx.INFO, "filling ngx.ctx ...") -local ok, ret, errors = helpers.fill_ctx() -if not ok then - logger:log(ngx.ERR, "fill_ctx() failed : " .. ret) -elseif errors then - for i, error in ipairs(errors) do - logger:log(ngx.ERR, "fill_ctx() error " .. tostring(i) .. " : " .. error) - end -end -logger:log(ngx.INFO, "ngx.ctx filled (ret = " .. ret .. ")") - --- Get plugins order -local order, err = datastore:get("plugins_order") -if not order then - logger:log(ngx.ERR, "can't get plugins order from datastore : " .. err) - return -end -order = cjson.decode(order) - --- Call log() methods -logger:log(ngx.INFO, "calling log() methods of plugins ...") -for i, plugin_id in ipairs(order.log) do - -- Require call - local plugin_lua, err = helpers.require_plugin(plugin_id) - if plugin_lua == false then - logger:log(ngx.ERR, err) - elseif plugin_lua == nil then - logger:log(ngx.INFO, err) - else - -- Check if plugin has log method - if plugin_lua.log ~= nil then - -- New call - local ok, plugin_obj = helpers.new_plugin(plugin_lua) - if not ok then - logger:log(ngx.ERR, plugin_obj) - else - local ok, ret = helpers.call_plugin(plugin_obj, "log") - if not ok then - logger:log(ngx.ERR, ret) - elseif not ret.ret then - logger:log(ngx.ERR, plugin_id .. ":log() call failed : " .. ret.msg) - else - logger:log(ngx.INFO, plugin_id .. ":log() call successful : " .. ret.msg) - end - end - else - logger:log(ngx.INFO, "skipped execution of " .. plugin_id .. " because method log() is not defined") + -- Fill ctx + logger:log(ngx.INFO, "filling ngx.ctx ...") + local ok, ret, errors, ctx = helpers.fill_ctx() + if not ok then + logger:log(ngx.ERR, "fill_ctx() failed : " .. ret) + elseif errors then + for i, error in ipairs(errors) do + logger:log(ngx.ERR, "fill_ctx() error " .. tostring(i) .. " : " .. error) end end -end -logger:log(ngx.INFO, "called log() methods of plugins") + logger:log(ngx.INFO, "ngx.ctx filled (ret = " .. ret .. ")") --- Display reason at info level -if ngx.ctx.reason then - logger:log(ngx.INFO, "client was denied with reason : " .. ngx.ctx.reason) -end + -- Get plugins order + local order, err = datastore:get("plugins_order", true) + if not order then + logger:log(ngx.ERR, "can't get plugins order from datastore : " .. err) + return + end -logger:log(ngx.INFO, "log phase ended") + -- Call log() methods + logger:log(ngx.INFO, "calling log() methods of plugins ...") + for i, plugin_id in ipairs(order.log) do + -- Require call + local plugin_lua, err = helpers.require_plugin(plugin_id) + if plugin_lua == false then + logger:log(ngx.ERR, err) + elseif plugin_lua == nil then + logger:log(ngx.INFO, err) + else + -- Check if plugin has log method + if plugin_lua.log ~= nil then + -- New call + local ok, plugin_obj = helpers.new_plugin(plugin_lua, ctx) + if not ok then + logger:log(ngx.ERR, plugin_obj) + else + local ok, ret = helpers.call_plugin(plugin_obj, "log") + if not ok then + logger:log(ngx.ERR, ret) + elseif not ret.ret then + logger:log(ngx.ERR, plugin_id .. ":log() call failed : " .. ret.msg) + else + logger:log(ngx.INFO, plugin_id .. ":log() call successful : " .. ret.msg) + end + end + else + logger:log(ngx.INFO, "skipped execution of " .. plugin_id .. " because method log() is not defined") + end + end + end + logger:log(ngx.INFO, "called log() methods of plugins") + -- Display reason at info level + if ctx.reason then + logger:log(ngx.INFO, "client was denied with reason : " .. ctx.reason) + end + + -- Save ctx + ngx.ctx = ctx + + logger:log(ngx.INFO, "log phase ended") } \ No newline at end of file diff --git a/src/common/confs/server-http/set-lua.conf b/src/common/confs/server-http/set-lua.conf index 4262454e5..b09953ec4 100644 --- a/src/common/confs/server-http/set-lua.conf +++ b/src/common/confs/server-http/set-lua.conf @@ -1,84 +1,84 @@ set $dummy_set ""; set_by_lua_block $dummy_set { + local class = require "middleclass" + local clogger = require "bunkerweb.logger" + local helpers = require "bunkerweb.helpers" + local cdatastore = require "bunkerweb.datastore" + local ccachestore = require "bunkerweb.cachestore" + local cjson = require "cjson" -local class = require "middleclass" -local clogger = require "bunkerweb.logger" -local helpers = require "bunkerweb.helpers" -local cdatastore = require "bunkerweb.datastore" -local ccachestore = require "bunkerweb.cachestore" -local cjson = require "cjson" - --- Don't process internal requests -local logger = clogger:new("SET") -if ngx.req.is_internal() then - logger:log(ngx.INFO, "skipped set phase because request is internal") - return true -end - --- Start set phase -local datastore = cdatastore:new() -logger:log(ngx.INFO, "set phase started") - --- Update cachestore only once and before any other code -local cachestore = ccachestore:new() -local ok, err = cachestore.cache:update() -if not ok then - logger:log(ngx.ERR, "can't update cachestore : " .. err) -end - --- Fill ctx -logger:log(ngx.INFO, "filling ngx.ctx ...") -local ok, ret, errors = helpers.fill_ctx() -if not ok then - logger:log(ngx.ERR, "fill_ctx() failed : " .. ret) -elseif errors then - for i, error in ipairs(errors) do - logger:log(ngx.ERR, "fill_ctx() error " .. tostring(i) .. " : " .. error) + -- Don't process internal requests + local logger = clogger:new("SET") + if ngx.req.is_internal() then + logger:log(ngx.INFO, "skipped set phase because request is internal") + return true end -end -logger:log(ngx.INFO, "ngx.ctx filled (ret = " .. ret .. ")") --- Get plugins order -local order, err = datastore:get("plugins_order") -if not order then - logger:log(ngx.ERR, "can't get plugins order from datastore : " .. err) - return -end -order = cjson.decode(order) + -- Start set phase + local datastore = cdatastore:new() + logger:log(ngx.INFO, "set phase started") --- Call set() methods -logger:log(ngx.INFO, "calling set() methods of plugins ...") -for i, plugin_id in ipairs(order.set) do - -- Require call - local plugin_lua, err = helpers.require_plugin(plugin_id) - if plugin_lua == false then - logger:log(ngx.ERR, err) - elseif plugin_lua == nil then - logger:log(ngx.INFO, err) - else - -- Check if plugin has set method - if plugin_lua.set ~= nil then - -- New call - local ok, plugin_obj = helpers.new_plugin(plugin_lua) - if not ok then - logger:log(ngx.ERR, plugin_obj) - else - local ok, ret = helpers.call_plugin(plugin_obj, "set") - if not ok then - logger:log(ngx.ERR, ret) - elseif not ret.ret then - logger:log(ngx.ERR, plugin_id .. ":set() call failed : " .. ret.msg) - else - logger:log(ngx.INFO, plugin_id .. ":set() call successful : " .. ret.msg) - end - end - else - logger:log(ngx.INFO, "skipped execution of " .. plugin_id .. " because method set() is not defined") + -- Update cachestore only once and before any other code + local cachestore = ccachestore:new() + local ok, err = cachestore.cache:update() + if not ok then + logger:log(ngx.ERR, "can't update cachestore : " .. err) + end + + -- Fill ctx + logger:log(ngx.INFO, "filling ngx.ctx ...") + local ok, ret, errors, ctx = helpers.fill_ctx() + if not ok then + logger:log(ngx.ERR, "fill_ctx() failed : " .. ret) + elseif errors then + for i, error in ipairs(errors) do + logger:log(ngx.ERR, "fill_ctx() error " .. tostring(i) .. " : " .. error) end end -end -logger:log(ngx.INFO, "called set() methods of plugins") + logger:log(ngx.INFO, "ngx.ctx filled (ret = " .. ret .. ")") -return true + -- Get plugins order + local order, err = datastore:get("plugins_order", true) + if not order then + logger:log(ngx.ERR, "can't get plugins order from datastore : " .. err) + return + end -} \ No newline at end of file + -- Call set() methods + logger:log(ngx.INFO, "calling set() methods of plugins ...") + for i, plugin_id in ipairs(order.set) do + -- Require call + local plugin_lua, err = helpers.require_plugin(plugin_id) + if plugin_lua == false then + logger:log(ngx.ERR, err) + elseif plugin_lua == nil then + logger:log(ngx.INFO, err) + else + -- Check if plugin has set method + if plugin_lua.set ~= nil then + -- New call + local ok, plugin_obj = helpers.new_plugin(plugin_lua, ctx) + if not ok then + logger:log(ngx.ERR, plugin_obj) + else + local ok, ret = helpers.call_plugin(plugin_obj, "set") + if not ok then + logger:log(ngx.ERR, ret) + elseif not ret.ret then + logger:log(ngx.ERR, plugin_id .. ":set() call failed : " .. ret.msg) + else + logger:log(ngx.INFO, plugin_id .. ":set() call successful : " .. ret.msg) + end + end + else + logger:log(ngx.INFO, "skipped execution of " .. plugin_id .. " because method set() is not defined") + end + end + end + logger:log(ngx.INFO, "called set() methods of plugins") + + -- Save ctx + ngx.ctx = ctx + + return true +} diff --git a/src/common/confs/server-stream/log-stream-lua.conf b/src/common/confs/server-stream/log-stream-lua.conf index ee9da1e46..73d434dc3 100644 --- a/src/common/confs/server-stream/log-stream-lua.conf +++ b/src/common/confs/server-stream/log-stream-lua.conf @@ -1,74 +1,74 @@ log_by_lua_block { + local class = require "middleclass" + local clogger = require "bunkerweb.logger" + local helpers = require "bunkerweb.helpers" + local cdatastore = require "bunkerweb.datastore" + local cjson = require "cjson" -local class = require "middleclass" -local clogger = require "bunkerweb.logger" -local helpers = require "bunkerweb.helpers" -local cdatastore = require "bunkerweb.datastore" -local cjson = require "cjson" + -- Start log phase + local logger = clogger:new("LOG") + local datastore = cdatastore:new() + logger:log(ngx.INFO, "log phase started") --- Start log phase -local logger = clogger:new("LOG") -local datastore = cdatastore:new() -logger:log(ngx.INFO, "log phase started") - --- Fill ctx -logger:log(ngx.INFO, "filling ngx.ctx ...") -local ok, ret, errors = helpers.fill_ctx() -if not ok then - logger:log(ngx.ERR, "fill_ctx() failed : " .. ret) -elseif errors then - for i, error in ipairs(errors) do - logger:log(ngx.ERR, "fill_ctx() error " .. tostring(i) .. " : " .. error) - end -end -logger:log(ngx.INFO, "ngx.ctx filled (ret = " .. ret .. ")") - --- Get plugins order -local order, err = datastore:get("plugins_order") -if not order then - logger:log(ngx.ERR, "can't get plugins order from datastore : " .. err) - return -end -order = cjson.decode(order) - --- Call log_stream() methods -logger:log(ngx.INFO, "calling log_stream() methods of plugins ...") -for i, plugin_id in ipairs(order.log_stream) do - -- Require call - local plugin_lua, err = helpers.require_plugin(plugin_id) - if plugin_lua == false then - logger:log(ngx.ERR, err) - elseif plugin_lua == nil then - logger:log(ngx.INFO, err) - else - -- Check if plugin has log_stream method - if plugin_lua.log_stream ~= nil then - -- New call - local ok, plugin_obj = helpers.new_plugin(plugin_lua) - if not ok then - logger:log(ngx.ERR, plugin_obj) - else - local ok, ret = helpers.call_plugin(plugin_obj, "log_stream") - if not ok then - logger:log(ngx.ERR, ret) - elseif not ret.ret then - logger:log(ngx.ERR, plugin_id .. ":log_stream() call failed : " .. ret.msg) - else - logger:log(ngx.INFO, plugin_id .. ":log_stream() call successful : " .. ret.msg) - end - end - else - logger:log(ngx.INFO, "skipped execution of " .. plugin_id .. " because method log_stream() is not defined") + -- Fill ctx + logger:log(ngx.INFO, "filling ngx.ctx ...") + local ok, ret, errors, ctx = helpers.fill_ctx() + if not ok then + logger:log(ngx.ERR, "fill_ctx() failed : " .. ret) + elseif errors then + for i, error in ipairs(errors) do + logger:log(ngx.ERR, "fill_ctx() error " .. tostring(i) .. " : " .. error) end end -end -logger:log(ngx.INFO, "called log_stream() methods of plugins") + logger:log(ngx.INFO, "ngx.ctx filled (ret = " .. ret .. ")") --- Display reason at info level -if ngx.ctx.reason then - logger:log(ngx.INFO, "client was denied with reason : " .. ngx.ctx.reason) -end + -- Get plugins order + local order, err = datastore:get("plugins_order", true) + if not order then + logger:log(ngx.ERR, "can't get plugins order from datastore : " .. err) + return + end -logger:log(ngx.INFO, "log phase ended") + -- Call log_stream() methods + logger:log(ngx.INFO, "calling log_stream() methods of plugins ...") + for i, plugin_id in ipairs(order.log_stream) do + -- Require call + local plugin_lua, err = helpers.require_plugin(plugin_id) + if plugin_lua == false then + logger:log(ngx.ERR, err) + elseif plugin_lua == nil then + logger:log(ngx.INFO, err) + else + -- Check if plugin has log_stream method + if plugin_lua.log_stream ~= nil then + -- New call + local ok, plugin_obj = helpers.new_plugin(plugin_lua, ctx) + if not ok then + logger:log(ngx.ERR, plugin_obj) + else + local ok, ret = helpers.call_plugin(plugin_obj, "log_stream") + if not ok then + logger:log(ngx.ERR, ret) + elseif not ret.ret then + logger:log(ngx.ERR, plugin_id .. ":log_stream() call failed : " .. ret.msg) + else + logger:log(ngx.INFO, plugin_id .. ":log_stream() call successful : " .. ret.msg) + end + end + else + logger:log(ngx.INFO, "skipped execution of " .. plugin_id .. " because method log_stream() is not defined") + end + end + end + logger:log(ngx.INFO, "called log_stream() methods of plugins") -} \ No newline at end of file + -- Display reason at info level + if ctx.reason then + logger:log(ngx.INFO, "client was denied with reason : " .. ctx.reason) + end + + -- Save ctx + ngx.ctx = ctx + + logger:log(ngx.INFO, "log phase ended") +} diff --git a/src/common/confs/server-stream/preread-stream-lua.conf b/src/common/confs/server-stream/preread-stream-lua.conf index b04bbb0fa..9337845f8 100644 --- a/src/common/confs/server-stream/preread-stream-lua.conf +++ b/src/common/confs/server-stream/preread-stream-lua.conf @@ -1,104 +1,104 @@ preread_by_lua_block { + ngx.ctx + local class = require "middleclass" + local clogger = require "bunkerweb.logger" + local helpers = require "bunkerweb.helpers" + local utils = require "bunkerweb.utils" + local cdatastore = require "bunkerweb.datastore" + local cclusterstore = require "bunkerweb.clusterstore" + local cjson = require "cjson" -local class = require "middleclass" -local clogger = require "bunkerweb.logger" -local helpers = require "bunkerweb.helpers" -local utils = require "bunkerweb.utils" -local cdatastore = require "bunkerweb.datastore" -local cclusterstore = require "bunkerweb.clusterstore" -local cjson = require "cjson" + -- Start preread phase + local logger = clogger:new("PREREAD") + local datastore = cdatastore:new() + logger:log(ngx.INFO, "preread phase started") --- Start preread phase -local logger = clogger:new("PREREAD") -local datastore = cdatastore:new() -logger:log(ngx.INFO, "preread phase started") - --- Fill ctx -logger:log(ngx.INFO, "filling ngx.ctx ...") -local ok, ret, errors = helpers.fill_ctx() -if not ok then - logger:log(ngx.ERR, "fill_ctx() failed : " .. ret) -elseif errors then - for i, error in ipairs(errors) do - logger:log(ngx.ERR, "fill_ctx() error " .. tostring(i) .. " : " .. error) - end -end -logger:log(ngx.INFO, "ngx.ctx filled (ret = " .. ret .. ")") - --- Process bans as soon as possible -local banned, reason, ttl = utils.is_banned(ngx.ctx.bw.remote_addr) -if banned == nil then - logger:log(ngx.ERR, "can't check if IP " .. ngx.ctx.bw.remote_addr .. " is banned : " .. reason) -elseif banned then - logger:log(ngx.WARN, "IP " .. ngx.ctx.bw.remote_addr .. " is banned with reason " .. reason .. " (" .. tostring(ttl) .. "s remaining)") - return ngx.exit(utils.get_deny_status()) -else - logger:log(ngx.INFO, "IP " .. ngx.ctx.bw.remote_addr .. " is not banned") -end - --- Get plugins order -local order, err = datastore:get("plugins_order") -if not order then - logger:log(ngx.ERR, "can't get plugins order from datastore : " .. err) - local ok, err = lock:unlock() + -- Fill ctx + logger:log(ngx.INFO, "filling ngx.ctx ...") + local ok, ret, errors, ctx = helpers.fill_ctx() if not ok then - logger:log(ngx.ERR, "lock:unlock() failed : " .. err) - end - return -end -order = cjson.decode(order) - --- Call preread() methods -logger:log(ngx.INFO, "calling preread() methods of plugins ...") -local status = nil -for i, plugin_id in ipairs(order.preread) do - -- Require call - local plugin_lua, err = helpers.require_plugin(plugin_id) - if plugin_lua == false then - logger:log(ngx.ERR, err) - elseif plugin_lua == nil then - logger:log(ngx.INFO, err) - else - -- Check if plugin has preread method - if plugin_lua.preread ~= nil then - -- New call - local ok, plugin_obj = helpers.new_plugin(plugin_lua) - if not ok then - logger:log(ngx.ERR, plugin_obj) - else - local ok, ret = helpers.call_plugin(plugin_obj, "preread") - if not ok then - logger:log(ngx.ERR, ret) - elseif not ret.ret then - logger:log(ngx.ERR, plugin_id .. ":preread() call failed : " .. ret.msg) - else - logger:log(ngx.INFO, plugin_id .. ":preread() call successful : " .. ret.msg) - end - if ret.status then - if ret.status == utils.get_deny_status() then - ngx.ctx.reason = plugin_id - logger:log(ngx.WARN, "denied preread from " .. plugin_id .. " : " .. ret.msg) - else - logger:log(ngx.NOTICE, plugin_id .. " returned status " .. tostring(ret.status) .. " : " .. ret.msg) - end - status = ret.status - break - end - end - else - logger:log(ngx.INFO, "skipped execution of " .. plugin_id .. " because method preread() is not defined") + logger:log(ngx.ERR, "fill_ctx() failed : " .. ret) + elseif errors then + for i, error in ipairs(errors) do + logger:log(ngx.ERR, "fill_ctx() error " .. tostring(i) .. " : " .. error) end end -end -logger:log(ngx.INFO, "called preread() methods of plugins") + logger:log(ngx.INFO, "ngx.ctx filled (ret = " .. ret .. ")") -logger:log(ngx.INFO, "preread phase ended") + -- Process bans as soon as possible + if ctx.bw.is_whitelisted ~= "yes" then + local banned, reason, ttl = utils.is_banned(ctx.bw.remote_addr) + if banned == nil then + logger:log(ngx.ERR, "can't check if IP " .. ctx.bw.remote_addr .. " is banned : " .. reason) + elseif banned then + logger:log(ngx.WARN, + "IP " .. ctx.bw.remote_addr .. " is banned with reason " .. reason .. " (" .. tostring(ttl) .. "s remaining)") + return ngx.exit(utils.get_deny_status()) + else + logger:log(ngx.INFO, "IP " .. ctx.bw.remote_addr .. " is not banned") + end + end --- Return status if needed -if status then - return ngx.exit(status) -end + -- Get plugins order + local order, err = datastore:get("plugins_order", true) + if not order then + logger:log(ngx.ERR, "can't get plugins order from datastore : " .. err) + return + end -return true + -- Call preread() methods + logger:log(ngx.INFO, "calling preread() methods of plugins ...") + local status = nil + for i, plugin_id in ipairs(order.preread) do + -- Require call + local plugin_lua, err = helpers.require_plugin(plugin_id) + if plugin_lua == false then + logger:log(ngx.ERR, err) + elseif plugin_lua == nil then + logger:log(ngx.INFO, err) + else + -- Check if plugin has preread method + if plugin_lua.preread ~= nil then + -- New call + local ok, plugin_obj = helpers.new_plugin(plugin_lua, ctx) + if not ok then + logger:log(ngx.ERR, plugin_obj) + else + local ok, ret = helpers.call_plugin(plugin_obj, "preread") + if not ok then + logger:log(ngx.ERR, ret) + elseif not ret.ret then + logger:log(ngx.ERR, plugin_id .. ":preread() call failed : " .. ret.msg) + else + logger:log(ngx.INFO, plugin_id .. ":preread() call successful : " .. ret.msg) + end + if ret.status then + if ret.status == utils.get_deny_status(ctx) then + ctx.bw.reason = plugin_id + logger:log(ngx.WARN, "denied preread from " .. plugin_id .. " : " .. ret.msg) + else + logger:log(ngx.NOTICE, plugin_id .. " returned status " .. tostring(ret.status) .. " : " .. ret.msg) + end + status = ret.status + break + end + end + else + logger:log(ngx.INFO, "skipped execution of " .. plugin_id .. " because method preread() is not defined") + end + end + end + logger:log(ngx.INFO, "called preread() methods of plugins") -} \ No newline at end of file + -- Save ctx + ngx.ctx = ctx + + logger:log(ngx.INFO, "preread phase ended") + + -- Return status if needed + if status then + return ngx.exit(status) + end + + return true +} diff --git a/src/common/core/antibot/antibot.lua b/src/common/core/antibot/antibot.lua index 07c235324..528620e18 100644 --- a/src/common/core/antibot/antibot.lua +++ b/src/common/core/antibot/antibot.lua @@ -1,23 +1,87 @@ -local class = require "middleclass" -local plugin = require "bunkerweb.plugin" -local utils = require "bunkerweb.utils" -local datastore = require "bunkerweb.datastore" -local cjson = require "cjson" -local captcha = require "antibot.captcha" -local base64 = require "base64" -local sha256 = require "resty.sha256" -local str = require "resty.string" -local http = require "resty.http" -local template = nil +local class = require "middleclass" +local plugin = require "bunkerweb.plugin" +local utils = require "bunkerweb.utils" +local cjson = require "cjson" +local captcha = require "antibot.captcha" +local base64 = require "base64" +local sha256 = require "resty.sha256" +local str = require "resty.string" +local http = require "resty.http" +local template = nil if ngx.shared.datastore then template = require "resty.template" end local antibot = class("antibot", plugin) -function antibot:initialize() +function antibot:initialize(ctx) -- Call parent initialize - plugin.initialize(self, "antibot") + plugin.initialize(self, "antibot", ctx) +end + +function antibot:header() + -- Check if access is needed + if self.variables["USE_ANTIBOT"] == "no" then + return self:ret(true, "antibot not activated") + end + -- Check if antibot uri + if self.ctx.bw.uri ~= self.variables["ANTIBOT_URI"] then + return self:ret(true, "Not antibot uri") + end + + -- Get session data + local session, err = utils.get_session("antibot", self.ctx) + if not session then + return self:ret(false, "can't get session : " .. err, ngx.HTTP_INTERNAL_SERVER_ERROR) + end + self.session = session + self.session_data = utils.get_session_data(self.session, true, self.ctx) + -- Check if session is valid + self:check_session() + + -- Don't go further if client resolved the challenge + if self.session_data.resolved then + if self.ctx.bw.uri == self.variables["ANTIBOT_URI"] then + return self:ret(true, "client already resolved the challenge", nil, self.session_data.original_uri) + end + return self:ret(true, "client already resolved the challenge") + end + + local header = "Content-Security-Policy" + if self.variables["CONTENT_SECURITY_POLICY_REPORT_ONLY"] == "yes" then + header = header .. "-Report-Only" + end + + if self.session_data.type == "recaptcha" then + ngx.header[header] = + "default-src 'none'; form-action 'self'; script-src 'strict-dynamic' 'nonce-" .. + self.session_data.nonce_script .. + "' https://www.google.com/recaptcha/ https://www.gstatic.com/recaptcha/ 'unsafe-inline' http: https:; img-src https://www.gstatic.com/recaptcha/ 'self' data:; frame-src https://www.google.com/recaptcha/ https://recaptcha.google.com/recaptcha/; style-src 'self' 'nonce-" .. + self.session_data.nonce_style .. + "'; font-src 'self' https://fonts.gstatic.com data:; base-uri 'self';" + elseif self.session_data.type == "hcaptcha" then + ngx.header[header] = + "default-src 'none'; form-action 'self'; script-src 'strict-dynamic' 'nonce-" .. + self.session_data.nonce_script .. + "' https://hcaptcha.com https://*.hcaptcha.com 'unsafe-inline' http: https:; img-src 'self' data:; frame-src https://hcaptcha.com https://*.hcaptcha.com; style-src 'self' 'nonce-" .. + self.session_data.nonce_style .. + "' https://hcaptcha.com https://*.hcaptcha.com; connect-src https://hcaptcha.com https://*.hcaptcha.com; font-src 'self' data:; base-uri 'self';" + elseif self.session_data.type == "turnstile" then + ngx.header[header] = + "default-src 'none'; form-action 'self'; script-src 'strict-dynamic' 'nonce-" .. + self.session_data.nonce_script .. + "' https://challenges.cloudflare.com 'unsafe-inline' http: https:; img-src 'self' data:; frame-src https://challenges.cloudflare.com; style-src 'self' 'nonce-" .. + self.session_data.nonce_style .. + "'; font-src 'self' data:; base-uri 'self';" + else + ngx.header[header] = + "default-src 'none'; form-action 'self'; script-src 'strict-dynamic' 'nonce-" .. + self.session_data.nonce_script .. + "' 'unsafe-inline' http: https:; img-src 'self' data:; style-src 'self' 'nonce-" .. + self.session_data.nonce_style .. + "'; font-src 'self' data:; base-uri 'self';" + end + return self:ret(true, "Successfully overridden CSP header") end function antibot:access() @@ -27,18 +91,18 @@ function antibot:access() end -- Get session data - local session, err = utils.get_session("antibot") + local session, err = utils.get_session("antibot", self.ctx) if not session then return self:ret(false, "can't get session : " .. err, ngx.HTTP_INTERNAL_SERVER_ERROR) end self.session = session - self.session_data = utils.get_session_data(self.session) + self.session_data = utils.get_session_data(self.session, true, self.ctx) -- Check if session is valid self:check_session() -- Don't go further if client resolved the challenge if self.session_data.resolved then - if ngx.ctx.bw.uri == self.variables["ANTIBOT_URI"] then + if self.ctx.bw.uri == self.variables["ANTIBOT_URI"] then return self:ret(true, "client already resolved the challenge", nil, self.session_data.original_uri) end return self:ret(true, "client already resolved the challenge") @@ -52,7 +116,7 @@ function antibot:access() end -- Redirect to challenge page - if ngx.ctx.bw.uri ~= self.variables["ANTIBOT_URI"] then + if self.ctx.bw.uri ~= self.variables["ANTIBOT_URI"] then return self:ret(true, "redirecting client to the challenge uri", nil, self.variables["ANTIBOT_URI"]) end @@ -62,13 +126,13 @@ function antibot:access() end -- Display challenge needed - if ngx.ctx.bw.request_method == "GET" then - ngx.ctx.bw.antibot_display_content = true + if self.ctx.bw.request_method == "GET" then + self.ctx.bw.antibot_display_content = true return self:ret(true, "displaying challenge to client", ngx.OK) end -- Check challenge - if ngx.ctx.bw.request_method == "POST" then + if self.ctx.bw.request_method == "POST" then local ok, err, redirect = self:check_challenge() local set_ok, set_err = self:set_session_data() if not set_ok then @@ -87,12 +151,12 @@ function antibot:access() if not ok then return self:ret(false, "can't save session : " .. err, ngx.HTTP_INTERNAL_SERVER_ERROR) end - ngx.ctx.bw.antibot_display_content = true + self.ctx.bw.antibot_display_content = true return self:ret(true, "displaying challenge to client", ngx.OK) end -- Method is suspicious, let's deny the request - return self:ret(true, "unsupported HTTP method for antibot", utils.get_deny_status()) + return self:ret(true, "unsupported HTTP method for antibot", utils.get_deny_status(self.ctx)) end function antibot:content() @@ -102,17 +166,17 @@ function antibot:content() end -- Check if display content is needed - if not ngx.ctx.bw.antibot_display_content then + if not self.ctx.bw.antibot_display_content then return self:ret(true, "display content not needed", nil, "/") end -- Get session data - local session, err = utils.get_session("antibot") + local session, err = utils.get_session("antibot", self.ctx) if not session then return self:ret(false, "can't get session : " .. err, ngx.HTTP_INTERNAL_SERVER_ERROR) end self.session = session - self.session_data = utils.get_session_data(self.session) + self.session_data = utils.get_session_data(self.session, true, self.ctx) -- Direct access without session if not self.session_data.prepared then @@ -155,7 +219,7 @@ end function antibot:set_session_data() if self.session_updated then - local ok, err = utils.set_session_data(self.session, self.session_data) + local ok, err = utils.set_session_data(self.session, self.session_data, true, self.ctx) if not ok then return false, err end @@ -172,16 +236,18 @@ function antibot:prepare_challenge() self.session_data.time_resolve = ngx.now() self.session_data.type = self.variables["USE_ANTIBOT"] self.session_data.resolved = false - self.session_data.original_uri = ngx.ctx.bw.request_uri - if ngx.ctx.bw.uri == self.variables["ANTIBOT_URI"] then + self.session_data.original_uri = self.ctx.bw.request_uri + self.session_data.nonce_script = utils.rand(16) + self.session_data.nonce_style = utils.rand(16) + if self.ctx.bw.uri == self.variables["ANTIBOT_URI"] then self.session_data.original_uri = "/" end - if self.variables["USE_ANTIBOT"] == "cookie" then + if self.session_data.type == "cookie" then self.session_data.resolved = true self.session_data.time_valid = ngx.now() - elseif self.variables["USE_ANTIBOT"] == "javascript" then + elseif self.session_data.type == "javascript" then self.session_data.random = utils.rand(20) - elseif self.variables["USE_ANTIBOT"] == "captcha" then + elseif self.session_data.type == "captcha" then self.session_data.captcha = utils.rand(6, true) end end @@ -195,16 +261,18 @@ function antibot:display_challenge() -- Common variables for templates local template_vars = { - antibot_uri = self.variables["ANTIBOT_URI"] + antibot_uri = self.variables["ANTIBOT_URI"], + nonce_script = self.session_data.nonce_script, + nonce_style = self.session_data.nonce_style, } -- Javascript case - if self.variables["USE_ANTIBOT"] == "javascript" then + if self.session_data.type == "javascript" then template_vars.random = self.session_data.random end -- Captcha case - if self.variables["USE_ANTIBOT"] == "captcha" then + if self.session_data.type == "captcha" then local chall_captcha = captcha.new() chall_captcha:font("/usr/share/bunkerweb/core/antibot/files/font.ttf") chall_captcha:string(self.session_data.captcha) @@ -213,17 +281,22 @@ function antibot:display_challenge() end -- reCAPTCHA case - if self.variables["USE_ANTIBOT"] == "recaptcha" then + if self.session_data.type == "recaptcha" then template_vars.recaptcha_sitekey = self.variables["ANTIBOT_RECAPTCHA_SITEKEY"] end -- hCaptcha case - if self.variables["USE_ANTIBOT"] == "hcaptcha" then + if self.session_data.type == "hcaptcha" then template_vars.hcaptcha_sitekey = self.variables["ANTIBOT_HCAPTCHA_SITEKEY"] end + -- Turnstile case + if self.session_data.type == "turnstile" then + template_vars.turnstile_sitekey = self.variables["ANTIBOT_TURNSTILE_SITEKEY"] + end + -- Render content - template.render(self.variables["USE_ANTIBOT"] .. ".html", template_vars) + template.render(self.session_data.type .. ".html", template_vars) return true, "displayed challenge" end @@ -235,14 +308,12 @@ function antibot:check_challenge() end local resolved = false - local err = "" - local redirect = nil self.session_data.prepared = false self.session_updated = true -- Javascript case - if self.variables["USE_ANTIBOT"] == "javascript" then + if self.session_data.type == "javascript" then ngx.req.read_body() local args, err = ngx.req.get_post_args(1) if err == "truncated" or not args or not args["challenge"] then @@ -261,7 +332,7 @@ function antibot:check_challenge() end -- Captcha case - if self.variables["USE_ANTIBOT"] == "captcha" then + if self.session_data.type == "captcha" then ngx.req.read_body() local args, err = ngx.req.get_post_args(1) if err == "truncated" or not args or not args["captcha"] then @@ -276,7 +347,7 @@ function antibot:check_challenge() end -- reCAPTCHA case - if self.variables["USE_ANTIBOT"] == "recaptcha" then + if self.session_data.type == "recaptcha" then ngx.req.read_body() local args, err = ngx.req.get_post_args(1) if err == "truncated" or not args or not args["token"] then @@ -289,8 +360,8 @@ function antibot:check_challenge() local res, err = httpc:request_uri("https://www.google.com/recaptcha/api/siteverify", { method = "POST", body = "secret=" .. - self.variables["ANTIBOT_RECAPTCHA_SECRET"] .. - "&response=" .. args["token"] .. "&remoteip=" .. ngx.ctx.bw.remote_addr, + self.variables["ANTIBOT_RECAPTCHA_SECRET"] .. + "&response=" .. args["token"] .. "&remoteip=" .. self.ctx.bw.remote_addr, headers = { ["Content-Type"] = "application/x-www-form-urlencoded" } @@ -312,7 +383,7 @@ function antibot:check_challenge() end -- hCaptcha case - if self.variables["USE_ANTIBOT"] == "hcaptcha" then + if self.session_data.type == "hcaptcha" then ngx.req.read_body() local args, err = ngx.req.get_post_args(1) if err == "truncated" or not args or not args["token"] then @@ -325,8 +396,8 @@ function antibot:check_challenge() local res, err = httpc:request_uri("https://hcaptcha.com/siteverify", { method = "POST", body = "secret=" .. - self.variables["ANTIBOT_HCAPTCHA_SECRET"] .. - "&response=" .. args["token"] .. "&remoteip=" .. ngx.ctx.bw.remote_addr, + self.variables["ANTIBOT_HCAPTCHA_SECRET"] .. + "&response=" .. args["token"] .. "&remoteip=" .. self.ctx.bw.remote_addr, headers = { ["Content-Type"] = "application/x-www-form-urlencoded" } @@ -347,6 +418,42 @@ function antibot:check_challenge() return true, "resolved", self.session_data.original_uri end + -- Turnstile case + if self.session_data.type == "turnstile" then + ngx.req.read_body() + local args, err = ngx.req.get_post_args(1) + if err == "truncated" or not args or not args["token"] then + return nil, "missing challenge arg", nil + end + local httpc, err = http.new() + if not httpc then + return nil, "can't instantiate http object : " .. err, nil, nil + end + local res, err = httpc:request_uri("https://challenges.cloudflare.com/turnstile/v0/siteverify", { + method = "POST", + body = "secret=" .. + self.variables["ANTIBOT_TURNSTILE_SECRET"] .. + "&response=" .. args["token"] .. "&remoteip=" .. self.ctx.bw.remote_addr, + headers = { + ["Content-Type"] = "application/x-www-form-urlencoded" + } + }) + httpc:close() + if not res then + return nil, "can't send request to Turnstile API : " .. err, nil + end + local ok, tdata = pcall(cjson.decode, res.body) + if not ok then + return nil, "error while decoding JSON from Turnstile API : " .. data, nil + end + if not tdata.success then + return false, "client failed challenge", nil + end + self.session_data.resolved = true + self.session_data.time_valid = ngx.now() + return true, "resolved", self.session_data.original_uri + end + return nil, "unknown", nil end diff --git a/src/common/core/antibot/confs/server-http/antibot.conf b/src/common/core/antibot/confs/server-http/antibot.conf index bf47d9b84..8480c67ab 100644 --- a/src/common/core/antibot/confs/server-http/antibot.conf +++ b/src/common/core/antibot/confs/server-http/antibot.conf @@ -3,17 +3,24 @@ location {{ ANTIBOT_URI }} { default_type 'text/html'; root /usr/share/bunkerweb/core/antibot/files; content_by_lua_block { - - local cantibot = require "antibot.antibot" - local clogger = require "bunkerweb.logger" - local antibot = cantibot:new() - local logger = clogger:new("ANTIBOT") - local ret = antibot:content() + local logger = require "bunkerweb.logger":new("ANTIBOT") + local helpers = require "bunkerweb.helpers" + local ok, ret, errors, ctx = helpers.fill_ctx() + if not ok then + logger:log(ngx.ERR, "fill_ctx() failed : " .. ret) + elseif errors then + for i, error in ipairs(errors) do + logger:log(ngx.ERR, "fill_ctx() error " .. tostring(i) .. " : " .. error) + end + end + local antibot = require "antibot.antibot":new(ctx) + local ret = antibot:content() if not ret.ret then logger:log(ngx.ERR, "antibot:content() failed : " .. ret.msg) else logger:log(ngx.INFO, "antibot:content() success : " .. ret.msg) end + ngx.ctx = ctx } } {% endif %} \ No newline at end of file diff --git a/src/common/core/antibot/files/captcha.html b/src/common/core/antibot/files/captcha.html index 0c24172f7..dd28fb010 100644 --- a/src/common/core/antibot/files/captcha.html +++ b/src/common/core/antibot/files/captcha.html @@ -1,241 +1,286 @@ -{-raw-} - - - - - - - Bot Detection - - - - - -
- / / / / / / / / / / / / / / / / / / / / / / / / / / -
- - - -
- / / / / / / / / / / / / / / / / / / / / / / / / / / -
- - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - -
- -
-

Please prove that you are Human before accessing this website

- {-raw-} -
- - {-raw-} - - -
-
- - - - -
- - - - - -{-raw-} \ No newline at end of file +{-raw-} + + + + + + + Bot Detection + + {-raw-} + + + + +
+ / / / / / / / / / / / / / / / / / / / / / / / / / / + +
+ + + +
+ / / / / / / / / / / / / / / / / / / / / / / / / / / + +
+ + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+

+ Please prove that you are Human before accessing this website +

+ {-raw-} +
+ + {-raw-} + + +
+
+ + + +
+ + + +{-raw-} diff --git a/src/common/core/antibot/files/hcaptcha.html b/src/common/core/antibot/files/hcaptcha.html index 14fbcda98..07341170e 100644 --- a/src/common/core/antibot/files/hcaptcha.html +++ b/src/common/core/antibot/files/hcaptcha.html @@ -7,38 +7,149 @@ Bot Detection - + rel="icon" + href="data:image/svg+xml, %3Csvg version='1.0' xmlns='http://www.w3.org/2000/svg' width='96.000000pt' height='96.000000pt' viewBox='0 0 96.000000 96.000000' preserveAspectRatio='xMidYMid meet'%3E%3Cg transform='translate(0.000000,96.000000) scale(0.100000,-0.100000)'%0Afill='%23085577' stroke='none'%3E%3Cpath d='M535 863 c-22 -2 -139 -17 -260 -34 -228 -31 -267 -43 -272 -85 -2%0A-10 23 -181 55 -379 l57 -360 400 0 400 0 20 40 c16 31 20 59 19 125 -1 100%0A-24 165 -73 199 -41 29 -46 57 -22 111 30 67 29 188 -3 256 -13 28 -37 60 -53%0A72 -55 39 -169 62 -268 55z m-15 -348 c30 -16 60 -61 60 -90 0 -10 -8 -33 -17%0A-52 -16 -34 -16 -41 0 -116 9 -44 15 -82 12 -85 -6 -7 -92 -21 -131 -21 l-31%0A-1 -6 85 c-4 75 -8 89 -31 112 -20 20 -26 36 -26 70 0 38 5 50 34 79 39 39 86%0A45 136 19z'/%3E%3C/g%3E%3C/svg%3E" + type="image/svg+xml" + /> + {-raw-} + - - + {-raw-} + + {-raw-} + -
- / / / / / / / / / / / / / / / / / / / / / / / / / / +
+ / / / / / / / / / / / / / / / / / / / / / / / / / / +
-
- / / / / / / / / / / / / / / / / / / / / / / / / / / +
+ / / / / / / / / / / / / / / / / / / / / / / / / / / +
-