diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml index 9bcc01329..e9f65d7b3 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/dev.yml @@ -47,7 +47,7 @@ jobs: exit-code: 1 ignore-unfixed: false severity: UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL - #trivyignores: .trivyignore + trivyignores: .trivyignore # BW scheduler tests scheduler: @@ -91,7 +91,7 @@ jobs: exit-code: 1 ignore-unfixed: false severity: UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL - #trivyignores: .trivyignore + trivyignores: .trivyignore # BW autoconf tests autoconf: @@ -135,7 +135,7 @@ jobs: exit-code: 1 ignore-unfixed: false severity: UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL - #trivyignores: .trivyignore + trivyignores: .trivyignore # BW UI tests ui: @@ -180,7 +180,7 @@ jobs: exit-code: 1 ignore-unfixed: false severity: UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL - #trivyignores: .trivyignore + trivyignores: .trivyignore # Python code security code-security: diff --git a/.trivyignore b/.trivyignore new file mode 100644 index 000000000..4be368d62 --- /dev/null +++ b/.trivyignore @@ -0,0 +1,4 @@ +# libcurl 7.87.0-r2 and curl 7.87.0-r2 are not yet available in python:3.11-alpine +CVE-2023-23916 +CVE-2023-23914 +CVE-2023-23915 \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 84674038f..6dc2e382c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,44 @@ # Changelog -## v1.4.3 - +## v1.4.6 + +- Fix error in the UI when a service have multiple domains +- Fix bwcli bans command +- Fix documentation about Linux Fedora install +- Fix DISABLE_DEFAULT_SERVER=yes not working with HTTPS +- Add INTERCEPTED_ERROR_CODES setting + +## v1.4.5 - 2022/11/26 + +- Fix bwcli syntax error +- Fix UI not working using Linux integration +- Fix missing openssl dep in autoconf +- Fix typo in selfsigned job + +## v1.4.4 - 2022/11/10 + +- Fix k8s controller not watching the events when there is an exception +- Fix python dependencies bug in CentOS and Fedora +- Fix incorrect log when reloading nginx using Linux integration +- Fix UI dev mode, production mode is now the default +- Fix wrong exposed port in the UI container +- Fix endless loading in the UI +- Fix \*_CUSTOM_CONF_\* dissapear when jobs are executed +- Fix various typos in documentation +- Fix warning about StartLimitIntervalSec directive when using Linux +- Fix incorrect log when issuing certbot renew +- Fix certbot renew error when using Linux or Docker integration +- Add greylist core feature +- Add BLACKLIST_IGNORE_\* settings +- Add automatic change of SecRequestBodyLimit modsec directive based on MAX_CLIENT_SIZE setting +- Add MODSECURITY_SEC_RULE_ENGINE and MODSECURITY_SEC_AUDIT_LOG_PARTS settings +- Add manual ban and get bans to the API/CLI +- Add Brawdunoir community example +- Improve core plugins order and add documentation about it +- Improve overall documentation +- Improve CI/CD + +## v1.4.3 - 2022/08/26 - Fix various documentation errors/typos and add various enhancements - Fix ui.env not read when using Linux integration diff --git a/README.md b/README.md index 0240b61be..dd370692d 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,12 @@

- BunkerWeb logo + BunkerWeb logo

- - - - + - - + +

@@ -30,7 +27,7 @@ > Make security by default great again ! -# Bunkerweb +# BunkerWeb

overview @@ -215,7 +212,7 @@ List of supported Linux distros : [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. -A specific BunkerWeb Ansible role is available on [Ansible Galaxy](https://galaxy.ansible.com/fl0ppy_d1sk/bunkerweb) (source code is available [here](https://github.com/bunkerity/bunkerweb-ansible)). +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/latest/integrations/#ansible) of the documentation. @@ -265,12 +262,12 @@ 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 | -| :------------: | :-----: | :------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------: | +| 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) | +| **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) | You will find more information in the [plugins section](https://docs.bunkerweb.io/latest/plugins) of the documentation. @@ -309,4 +306,4 @@ If you would like to contribute to the plugins you can read the [contributing gu # Security policy -We take security bugs as serious issues and encourage responsible disclosure, see our [security policy](https://github.com/bunkerity/bunkerweb/tree/master/SECURITY.md) for more information. +We take security bugs as serious issues and encourage responsible disclosure, see our [security policy](https://github.com/bunkerity/bunkerweb/tree/master/SECURITY.md) for more information. \ No newline at end of file diff --git a/docs/backup-new-integrations.md b/docs/backup-new-integrations.md index 062900669..f8378c6c6 100644 --- a/docs/backup-new-integrations.md +++ b/docs/backup-new-integrations.md @@ -17,13 +17,13 @@ sudo dnf install nginx-1.20.2 ``` - And finally install BunkerWeb 1.4.4 : + And finally install BunkerWeb 1.4.6 : ```shell wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm && \ rpm -Uvh epel-release*rpm && \ curl -s https://packagecloud.io/install/repositories/bunkerity/bunkerweb/script.rpm.sh | sudo bash && \ sudo dnf check-update && \ - sudo dnf install -y bunkerweb-1.4.4 + sudo dnf install -y bunkerweb-1.4.6 ``` To prevent upgrading NGINX and/or BunkerWeb packages when executing `dnf upgrade`, you can use the following command : diff --git a/docs/integrations.md b/docs/integrations.md index 4ff7e9423..94105de6f 100644 --- a/docs/integrations.md +++ b/docs/integrations.md @@ -12,7 +12,7 @@ Using BunkerWeb as a [Docker](https://www.docker.com/) container is a quick and We provide ready-to-use prebuilt images for x64, x86 armv8 and armv7 architectures on [Docker Hub](https://hub.docker.com/r/bunkerity/bunkerweb) : ```shell -docker pull bunkerity/bunkerweb:1.4.4 +docker pull bunkerity/bunkerweb:1.4.6 ``` Alternatively, you can build the Docker images directly from the [source](https://github.com/bunkerity/bunkerweb) (and get a coffee ☕ because it may take a long time depending on your hardware) : @@ -39,7 +39,7 @@ docker run \ -e MY_SETTING=value \ -e "MY_OTHER_SETTING=value with spaces" \ ... - bunkerity/bunkerweb:1.4.4 + bunkerity/bunkerweb:1.4.6 ``` Here is the docker-compose equivalent : @@ -48,7 +48,7 @@ Here is the docker-compose equivalent : ... services: mybunker: - image: bunkerity/bunkerweb:1.4.4 + image: bunkerity/bunkerweb:1.4.6 environment: - MY_SETTING=value ``` @@ -73,7 +73,7 @@ docker run \ ... -v bw_data:/data \ ... - bunkerity/bunkerweb:1.4.4 + bunkerity/bunkerweb:1.4.6 ``` Here is the docker-compose equivalent : @@ -82,7 +82,7 @@ Here is the docker-compose equivalent : ... services: mybunker: - image: bunkerity/bunkerweb:1.4.4 + image: bunkerity/bunkerweb:1.4.6 volumes: - bw_data:/data ... @@ -152,7 +152,7 @@ docker run \ ... --network mynetwork \ ... - bunkerity/bunkerweb:1.4.4 + bunkerity/bunkerweb:1.4.6 ``` You will also need to do the same with your web application(s). Please note that the other containers are accessible using their name as the hostname. @@ -163,7 +163,7 @@ Here is the docker-compose equivalent : ... services: mybunker: - image: bunkerity/bunkerweb:1.4.4 + image: bunkerity/bunkerweb:1.4.6 networks: - bw-net ... @@ -218,7 +218,7 @@ docker run \ -e SERVER_NAME= \ -e "API_WHITELIST_IP=127.0.0.0/8 10.20.30.0/24" \ -l bunkerweb.AUTOCONF \ - bunkerity/bunkerweb:1.4.4 && \ + bunkerity/bunkerweb:1.4.6 && \ docker network connect bw-services mybunker ``` @@ -235,7 +235,7 @@ docker run \ --network bw-autoconf \ -v bw-data:/data \ -v /var/run/docker.sock:/var/run/docker.sock:ro \ - bunkerity/bunkerweb-autoconf:1.4.4 + bunkerity/bunkerweb-autoconf:1.4.6 ``` Here is the docker-compose equivalent for the BunkerWeb autoconf stack : @@ -246,7 +246,7 @@ version: '3.5' services: mybunker: - image: bunkerity/bunkerweb:1.4.4 + image: bunkerity/bunkerweb:1.4.6 ports: - 80:8080 - 443:8443 @@ -262,7 +262,7 @@ services: - bw-services myautoconf: - image: bunkerity/bunkerweb-autoconf:1.4.4 + image: bunkerity/bunkerweb-autoconf:1.4.6 volumes: - bw-data:/data - /var/run/docker.sock:/var/run/docker.sock:ro @@ -364,7 +364,7 @@ docker service create \ -e MULTISITE=yes \ -e "API_WHITELIST_IP=127.0.0.0/8 10.20.30.0/24" \ -l bunkerweb.AUTOCONF \ - bunkerity/bunkerweb:1.4.4 + bunkerity/bunkerweb:1.4.6 ``` And the autoconf one : @@ -378,7 +378,7 @@ docker service \ --mount type=bind,source=/var/run/docker.sock,destination=/var/run/docker.sock,ro \ --mount type=volume,source=bw-data,destination=/data \ -e SWARM_MODE=yes \ - bunkerity/bunkerweb-autoconf:1.4.4 + bunkerity/bunkerweb-autoconf:1.4.6 ``` Here is the docker-compose equivalent (using `docker stack deploy`) : @@ -389,7 +389,7 @@ version: '3.5' services: mybunker: - image: bunkerity/bunkerweb:1.4.4 + image: bunkerity/bunkerweb:1.4.6 ports: - published: 80 target: 8080 @@ -416,7 +416,7 @@ services: - "bunkerweb.AUTOCONF" myautoconf: - image: bunkerity/bunkerweb-autoconf:1.4.4 + image: bunkerity/bunkerweb-autoconf:1.4.6 environment: - SWARM_MODE=yes volumes: @@ -706,11 +706,11 @@ Repositories of Linux packages for BunkerWeb are available on [PackageCloud](htt sudo apt install -y nginx=1.20.2-1~$(lsb_release -cs) ``` - And finally install BunkerWeb 1.4.4 : + And finally install BunkerWeb 1.4.6 : ```shell curl -s https://packagecloud.io/install/repositories/bunkerity/bunkerweb/script.deb.sh | sudo bash && \ sudo apt update && \ - sudo apt install -y bunkerweb=1.4.4 + sudo apt install -y bunkerweb=1.4.6 ``` To prevent upgrading NGINX and/or BunkerWeb packages when executing `apt upgrade`, you can use the following command : @@ -736,11 +736,11 @@ Repositories of Linux packages for BunkerWeb are available on [PackageCloud](htt sudo apt install -y nginx=1.20.2-1~jammy ``` - And finally install BunkerWeb 1.4.4 : + And finally install BunkerWeb 1.4.6 : ```shell curl -s https://packagecloud.io/install/repositories/bunkerity/bunkerweb/script.deb.sh | sudo bash && \ sudo apt update && \ - sudo apt install -y bunkerweb=1.4.4 + sudo apt install -y bunkerweb=1.4.6 ``` To prevent upgrading NGINX and/or BunkerWeb packages when executing `apt upgrade`, you can use the following command : @@ -755,13 +755,13 @@ Repositories of Linux packages for BunkerWeb are available on [PackageCloud](htt sudo dnf install -y nginx-1.20.2 ``` - And finally install BunkerWeb 1.4.4 : + And finally install BunkerWeb 1.4.6 : ```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.4.4 + sudo dnf install -y bunkerweb-1.4.6 ``` To prevent upgrading NGINX and/or BunkerWeb packages when executing `dnf upgrade`, you can use the following command : @@ -788,12 +788,12 @@ Repositories of Linux packages for BunkerWeb are available on [PackageCloud](htt sudo dnf install nginx-1.20.2 ``` - And finally install BunkerWeb 1.4.4 : + And finally install BunkerWeb 1.4.6 : ```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.4.4 + sudo dnf install -y bunkerweb-1.4.6 ``` To prevent upgrading NGINX and/or BunkerWeb packages when executing `dnf upgrade`, you can use the following command : @@ -931,7 +931,7 @@ Configuration of BunkerWeb is done by using specific role variables : | Name | Type | Description | Default value | |:-----:|:-----:|--------------|----------------| -| `bunkerweb_version` | string | Version of BunkerWeb to install. | `1.4.4` | +| `bunkerweb_version` | string | Version of BunkerWeb to install. | `1.4.6` | | `nginx_version` | string | Version of NGINX to install. | `1.20.2` | | `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` | diff --git a/docs/plugins.md b/docs/plugins.md index 90034f390..18100d102 100644 --- a/docs/plugins.md +++ b/docs/plugins.md @@ -53,13 +53,13 @@ The first step is to install the plugin by putting the plugin files inside the c ... -v "${PWD}/bw-data:/data" \ ... - bunkerity/bunkerweb:1.4.4 + bunkerity/bunkerweb:1.4.6 ``` Here is the docker-compose equivalent : ```yaml mybunker: - image: bunkerity/bunkerweb:1.4.4 + image: bunkerity/bunkerweb:1.4.6 volumes: - ./bw-data:/data ... diff --git a/docs/quickstart-guide.md b/docs/quickstart-guide.md index 65681b383..652d25498 100644 --- a/docs/quickstart-guide.md +++ b/docs/quickstart-guide.md @@ -54,7 +54,7 @@ You will find more settings about reverse proxy in the [settings section](/1.4/s -e USE_REVERSE_PROXY=yes \ -e REVERSE_PROXY_URL=/ \ -e REVERSE_PROXY_HOST=http://myapp \ - bunkerity/bunkerweb:1.4.4 + bunkerity/bunkerweb:1.4.6 ``` Here is the docker-compose equivalent : @@ -64,7 +64,7 @@ You will find more settings about reverse proxy in the [settings section](/1.4/s services: mybunker: - image: bunkerity/bunkerweb:1.4.4 + image: bunkerity/bunkerweb:1.4.6 ports: - 80:8080 - 443:8443 @@ -379,7 +379,7 @@ You will find more settings about reverse proxy in the [settings section](/1.4/s -e app1.example.com_REVERSE_PROXY_HOST=http://myapp1 \ -e app2.example.com_REVERSE_PROXY_HOST=http://myapp2 \ -e app3.example.com_REVERSE_PROXY_HOST=http://myapp3 \ - bunkerity/bunkerweb:1.4.4 + bunkerity/bunkerweb:1.4.6 ``` Here is the docker-compose equivalent : @@ -389,7 +389,7 @@ You will find more settings about reverse proxy in the [settings section](/1.4/s services: mybunker: - image: bunkerity/bunkerweb:1.4.4 + image: bunkerity/bunkerweb:1.4.6 ports: - 80:8080 - 443:8443 @@ -981,13 +981,13 @@ REAL_IP_HEADER=X-Forwarded-For -e "REAL_IP_FROM=1.2.3.0/24 100.64.0.0/16" \ -e REAL_IP_HEADER=X-Forwarded-For \ ... - bunkerity/bunkerweb:1.4.4 + bunkerity/bunkerweb:1.4.6 ``` Here is the docker-compose equivalent : ```yaml mybunker: - image: bunkerity/bunkerweb:1.4.4 + image: bunkerity/bunkerweb:1.4.6 ... environment: - USE_REAL_IP=yes @@ -1006,13 +1006,13 @@ REAL_IP_HEADER=X-Forwarded-For -e "REAL_IP_FROM=1.2.3.0/24 100.64.0.0/16" \ -e REAL_IP_HEADER=X-Forwarded-For \ ... - bunkerity/bunkerweb:1.4.4 + bunkerity/bunkerweb:1.4.6 ``` Here is the docker-compose equivalent : ```yaml mybunker: - image: bunkerity/bunkerweb:1.4.4 + image: bunkerity/bunkerweb:1.4.6 ... environment: - USE_REAL_IP=yes @@ -1031,13 +1031,13 @@ REAL_IP_HEADER=X-Forwarded-For -e "REAL_IP_FROM=1.2.3.0/24 100.64.0.0/16" \ -e REAL_IP_HEADER=X-Forwarded-For \ ... - bunkerity/bunkerweb:1.4.4 + bunkerity/bunkerweb:1.4.6 ``` Here is the docker-compose equivalent (using `docker stack deploy`) : ```yaml mybunker: - image: bunkerity/bunkerweb:1.4.4 + image: bunkerity/bunkerweb:1.4.6 ... environment: - USE_REAL_IP=yes @@ -1062,7 +1062,7 @@ REAL_IP_HEADER=X-Forwarded-For spec: containers: - name: bunkerweb - image: bunkerity/bunkerweb:1.4.4 + image: bunkerity/bunkerweb:1.4.6 ... env: - name: USE_REAL_IP @@ -1146,13 +1146,13 @@ REAL_IP_HEADER=proxy_protocol -e "REAL_IP_FROM=1.2.3.0/24 100.64.0.0/16" \ -e REAL_IP_HEADER=proxy_protocol \ ... - bunkerity/bunkerweb:1.4.4 + bunkerity/bunkerweb:1.4.6 ``` Here is the docker-compose equivalent : ```yaml mybunker: - image: bunkerity/bunkerweb:1.4.4 + image: bunkerity/bunkerweb:1.4.6 ... environment: - USE_REAL_IP=yes @@ -1173,13 +1173,13 @@ REAL_IP_HEADER=proxy_protocol -e "REAL_IP_FROM=1.2.3.0/24 100.64.0.0/16" \ -e REAL_IP_HEADER=proxy_protocol \ ... - bunkerity/bunkerweb:1.4.4 + bunkerity/bunkerweb:1.4.6 ``` Here is the docker-compose equivalent : ```yaml mybunker: - image: bunkerity/bunkerweb:1.4.4 + image: bunkerity/bunkerweb:1.4.6 ... environment: - USE_REAL_IP=yes @@ -1200,13 +1200,13 @@ REAL_IP_HEADER=proxy_protocol -e "REAL_IP_FROM=1.2.3.0/24 100.64.0.0/16" \ -e REAL_IP_HEADER=proxy_protocol \ ... - bunkerity/bunkerweb:1.4.4 + bunkerity/bunkerweb:1.4.6 ``` Here is the docker-compose equivalent (using `docker stack deploy`) : ```yaml mybunker: - image: bunkerity/bunkerweb:1.4.4 + image: bunkerity/bunkerweb:1.4.6 ... environment: - USE_REAL_IP=yes @@ -1232,7 +1232,7 @@ REAL_IP_HEADER=proxy_protocol spec: containers: - name: bunkerweb - image: bunkerity/bunkerweb:1.4.4 + image: bunkerity/bunkerweb:1.4.6 ... env: - name: USE_REAL_IP @@ -1327,7 +1327,7 @@ Some integrations offer a more convenient way of applying configurations such as Here is a dummy example using a docker-compose file : ```yaml mybunker: - image: bunkerity/bunkerweb:1.4.4 + image: bunkerity/bunkerweb:1.4.6 environment: - | CUSTOM_CONF_SERVER_HTTP_hello-world= @@ -1369,13 +1369,13 @@ Some integrations offer a more convenient way of applying configurations such as ... -v "${PWD}/bw-data:/data" \ ... - bunkerity/bunkerweb:1.4.4 + bunkerity/bunkerweb:1.4.6 ``` Here is the docker-compose equivalent : ```yaml mybunker: - image: bunkerity/bunkerweb:1.4.4 + image: bunkerity/bunkerweb:1.4.6 volumes: - ./bw-data:/data ... @@ -1436,13 +1436,13 @@ Some integrations offer a more convenient way of applying configurations such as ... -v "${PWD}/bw-data:/data" \ ... - bunkerity/bunkerweb-autoconf:1.4.4 + bunkerity/bunkerweb-autoconf:1.4.6 ``` Here is the docker-compose equivalent : ```yaml myautoconf: - image: bunkerity/bunkerweb-autoconf:1.4.4 + image: bunkerity/bunkerweb-autoconf:1.4.6 volumes: - ./bw-data:/data ... @@ -1622,7 +1622,7 @@ BunkerWeb supports PHP using external or remote [PHP-FPM](https://www.php.net/ma -e AUTO_LETS_ENCRYPT=yes \ -e REMOTE_PHP=myphp \ -e REMOTE_PHP_PATH=/app \ - bunkerity/bunkerweb:1.4.4 + bunkerity/bunkerweb:1.4.6 ``` Here is the docker-compose equivalent : @@ -1632,7 +1632,7 @@ BunkerWeb supports PHP using external or remote [PHP-FPM](https://www.php.net/ma services: mybunker: - image: bunkerity/bunkerweb:1.4.4 + image: bunkerity/bunkerweb:1.4.6 ports: - 80:8080 - 443:8443 @@ -1674,7 +1674,7 @@ BunkerWeb supports PHP using external or remote [PHP-FPM](https://www.php.net/ma ... -v "${PWD}/myapp:/app" \ ... - bunkerity/bunkerweb:1.4.4 + bunkerity/bunkerweb:1.4.6 ``` Once BunkerWeb and autoconf are ready, you will be able to create the PHP-FPM container, mount the application folder inside the container and configure it using specific labels : @@ -1738,7 +1738,7 @@ BunkerWeb supports PHP using external or remote [PHP-FPM](https://www.php.net/ma ... -v "/shared/myapp:/app" \ ... - bunkerity/bunkerweb:1.4.4 + bunkerity/bunkerweb:1.4.6 ``` Once BunkerWeb and autoconf are ready, you will be able to create the PHP-FPM service, mount the application folder inside the container and configure it using specific labels : @@ -1984,7 +1984,7 @@ BunkerWeb supports PHP using external or remote [PHP-FPM](https://www.php.net/ma -e app2.example.com_REMOTE_PHP_PATH=/app \ -e app3.example.com_REMOTE_PHP=myphp3 \ -e app3.example.com_REMOTE_PHP_PATH=/app \ - bunkerity/bunkerweb:1.4.4 + bunkerity/bunkerweb:1.4.6 ``` Here is the docker-compose equivalent : @@ -1994,7 +1994,7 @@ BunkerWeb supports PHP using external or remote [PHP-FPM](https://www.php.net/ma services: mybunker: - image: bunkerity/bunkerweb:1.4.4 + image: bunkerity/bunkerweb:1.4.6 ports: - 80:8080 - 443:8443 @@ -2055,7 +2055,7 @@ BunkerWeb supports PHP using external or remote [PHP-FPM](https://www.php.net/ma ... -v "${PWD}/myapps:/apps" \ ... - bunkerity/bunkerweb:1.4.4 + bunkerity/bunkerweb:1.4.6 ``` Once BunkerWeb and autoconf are ready, you will be able to create the PHP-FPM containers, mount the right application folder inside each container and configure them using specific labels : @@ -2179,7 +2179,7 @@ BunkerWeb supports PHP using external or remote [PHP-FPM](https://www.php.net/ma ... -v "/shared/myapps:/apps" \ ... - bunkerity/bunkerweb:1.4.4 + bunkerity/bunkerweb:1.4.6 ``` Once BunkerWeb and autoconf are ready, you will be able to create the PHP-FPM service, mount the application folder inside the container and configure it using specific labels : diff --git a/docs/web-ui.md b/docs/web-ui.md index 0bc6ac267..7851aea7e 100644 --- a/docs/web-ui.md +++ b/docs/web-ui.md @@ -76,7 +76,7 @@ Because the web UI is a web application, the recommended installation procedure -e "bwadm.example.com_REVERSE_PROXY_HEADERS=X-Script-Name /changeme" \ -e bwadm.example.com_REVERSE_PROXY_INTERCEPT_ERRORS=no \ -l bunkerweb.UI \ - bunkerity/bunkerweb:1.4.4 && \ + bunkerity/bunkerweb:1.4.6 && \ docker network connect bw-ui mybunker ``` @@ -115,7 +115,7 @@ Because the web UI is a web application, the recommended installation procedure -e ADMIN_USERNAME=admin \ -e ADMIN_PASSWORD=changeme \ -e ABSOLUTE_URI=http(s)://bwadm.example.com/changeme/ \ - bunkerity/bunkerweb-ui:1.4.4 && \ + bunkerity/bunkerweb-ui:1.4.6 && \ docker network connect bw-docker myui ``` @@ -131,7 +131,7 @@ Because the web UI is a web application, the recommended installation procedure services: mybunker: - image: bunkerity/bunkerweb:1.4.4 + image: bunkerity/bunkerweb:1.4.6 networks: - bw-services - bw-ui @@ -154,7 +154,7 @@ Because the web UI is a web application, the recommended installation procedure - "bunkerweb.UI" myui: - image: bunkerity/bunkerweb-ui:1.4.4 + image: bunkerity/bunkerweb-ui:1.4.6 depends_on: - mydocker networks: diff --git a/examples/autoconf-configs/tests.json b/examples/autoconf-configs/tests.json index 530e3d36e..5c4596e1f 100644 --- a/examples/autoconf-configs/tests.json +++ b/examples/autoconf-configs/tests.json @@ -1,6 +1,7 @@ { "name": "autoconf-configs", "kinds": ["autoconf"], + "delay": 60, "timeout": 60, "tests": [ { diff --git a/examples/drupal/setup-linux.sh b/examples/drupal/setup-linux.sh index 1f56b43bc..5b2e0f04c 100755 --- a/examples/drupal/setup-linux.sh +++ b/examples/drupal/setup-linux.sh @@ -13,7 +13,7 @@ else echo "❌ No PHP user found" exit 1 fi -curl https://www.drupal.org/download-latest/tar.gz -Lo /tmp/drupal.tar.gz +curl https://ftp.drupal.org/files/projects/drupal-9.5.3.tar.gz -Lo /tmp/drupal.tar.gz tar -xzf /tmp/drupal.tar.gz -C /tmp current_dir="$(pwd)" cd /tmp/drupal-* diff --git a/examples/ghost/tests.json b/examples/ghost/tests.json index 0fbaa943b..b96fecbf2 100644 --- a/examples/ghost/tests.json +++ b/examples/ghost/tests.json @@ -2,7 +2,7 @@ "name": "ghost", "kinds": ["docker", "autoconf", "swarm", "kubernetes"], "timeout": 60, - "delay": 180, + "delay": 240, "tests": [ { "type": "string", diff --git a/examples/mattermost/.env b/examples/mattermost/.env index 0529e673f..66838c17c 100644 --- a/examples/mattermost/.env +++ b/examples/mattermost/.env @@ -60,7 +60,7 @@ MM_BLEVESETTINGS_INDEXDIR=/mattermost/bleve-indexes ## This will be 'mattermost-enterprise-edition' or 'mattermost-team-edition' based on the version of Mattermost you're installing. MATTERMOST_IMAGE=mattermost-enterprise-edition -MATTERMOST_IMAGE_TAG=master +MATTERMOST_IMAGE_TAG=7.7.1 ## Make Mattermost container readonly. This interferes with the regeneration of root.html inside the container. Only use ## it if you know what you're doing. diff --git a/examples/nextcloud/kubernetes.yml b/examples/nextcloud/kubernetes.yml index 32841e724..89373ae7f 100644 --- a/examples/nextcloud/kubernetes.yml +++ b/examples/nextcloud/kubernetes.yml @@ -7,7 +7,7 @@ metadata: bunkerweb.io/www.example.com_MAX_CLIENT_SIZE: "10G" bunkerweb.io/www.example.com_ALLOWED_METHODS: "GET|POST|HEAD|COPY|DELETE|LOCK|MKCOL|MOVE|PROPFIND|PROPPATCH|PUT|UNLOCK|OPTIONS" bunkerweb.io/www.example.com_X_FRAME_OPTIONS: "SAMEORIGIN" - bunkerweb.io/www.example.com_BAD_BEHAVIOR_STATUS_CODES: "400 401.4.4 405 444" + bunkerweb.io/www.example.com_BAD_BEHAVIOR_STATUS_CODES: "400 401 405 444" bunkerweb.io/www.example.com_LIMIT_REQ_URL_1: "/apps" bunkerweb.io/www.example.com_LIMIT_REQ_RATE_1: "5r/s" bunkerweb.io/www.example.com_LIMIT_REQ_URL_2: "/apps/text/session/sync" diff --git a/src/autoconf/Dockerfile b/src/autoconf/Dockerfile index c80332100..dd3a139cb 100644 --- a/src/autoconf/Dockerfile +++ b/src/autoconf/Dockerfile @@ -54,7 +54,7 @@ RUN apk add --no-cache bash && \ chmod 770 /var/log/letsencrypt /var/lib/letsencrypt # Fix CVEs -RUN apk add "libssl1.1>=1.1.1q-r0" "libcrypto1.1>=1.1.1q-r0" "git>=2.32.3-r0" "libxml2>=2.9.14-r1" "expat>=2.5.0-r0" +RUN apk add "libssl1.1>=1.1.1q-r0" "libcrypto1.1>=1.1.1q-r0" "libxml2>=2.9.14-r1" "expat>=2.5.0-r0" "git>=2.36.5-r0" VOLUME /data /etc/nginx diff --git a/src/bw/Dockerfile b/src/bw/Dockerfile index 74ba9d9b8..8cf383dc8 100644 --- a/src/bw/Dockerfile +++ b/src/bw/Dockerfile @@ -4,22 +4,22 @@ FROM nginx:1.22.1-alpine AS builder COPY src/deps /tmp/bunkerweb/deps # Compile and install dependencies -RUN apk add --no-cache --virtual build bash build 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 && \ +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 && \ chmod +x /tmp/bunkerweb/deps/install.sh && \ bash /tmp/bunkerweb/deps/install.sh && \ - apk del build + apk del .build-deps # 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 py3-pip && \ +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 && \ pip install --no-cache-dir --require-hashes --target /usr/share/bunkerweb/deps/python -r /usr/share/bunkerweb/deps/requirements.txt && \ - apk del build + apk del .build-deps FROM nginx:1.22.1-alpine @@ -75,7 +75,7 @@ RUN apk add --no-cache pcre bash python3 && \ chmod 660 /usr/share/bunkerweb/INTEGRATION # Fix CVEs -RUN apk add "openssl>=1.1.1q-r0" "curl>=7.83.1-r5" "git>=2.36.4-r0" "libcurl>=7.83.1-r5" "git>=2.36.5-r0" +RUN apk add "openssl>=1.1.1q-r0" "curl>=7.83.1-r6" "libcurl>=7.83.1-r6" "git>=2.36.5-r0" VOLUME /data /etc/nginx diff --git a/src/common/confs/default-server-http.conf b/src/common/confs/default-server-http.conf index a9dc6630f..5e7b01012 100644 --- a/src/common/confs/default-server-http.conf +++ b/src/common/confs/default-server-http.conf @@ -10,6 +10,15 @@ server { listen 0.0.0.0:{{ HTTP_PORT }} default_server {% if USE_PROXY_PROTOCOL == "yes" %}proxy_protocol{% endif %}; {% endif %} + # HTTPS listen +{% set os = import("os") %} +{% if os.path.isfile("/var/cache/bunkerweb/default-server-cert/cert.pem") +%} + {% if has_variable(all, "USE_CUSTOM_HTTPS", "yes") or has_variable(all, "AUTO_LETS_ENCRYPT", "yes") or has_variable(all, "GENERATE_SELF_SIGNED_SSL", "yes") +%} + listen 0.0.0.0:{{ HTTPS_PORT }} ssl {% if HTTP2 == "yes" %}http2{% endif %} default_server {% if USE_PROXY_PROTOCOL == "yes" %}proxy_protocol{% endif %}; + ssl_certificate /var/cache/bunkerweb/selfsigned/{{ SERVER_NAME.split(" ")[0] }}.pem; + ssl_certificate_key /var/cache/bunkerweb/selfsigned/{{ SERVER_NAME.split(" ")[0] }}.key; + {% endif %} +{% endif %} {% if IS_LOADING == "yes" +%} root /usr/share/bunkerweb/loading; diff --git a/src/common/core/bunkernet/jobs/bunkernet-data.py b/src/common/core/bunkernet/jobs/bunkernet-data.py index 65574b59b..80a4aa3f2 100755 --- a/src/common/core/bunkernet/jobs/bunkernet-data.py +++ b/src/common/core/bunkernet/jobs/bunkernet-data.py @@ -78,6 +78,11 @@ try: "BunkerNet API is rate limiting us, trying again later...", ) _exit(0) + elif status == 403: + logger.warning( + "BunkerNet has banned this instance, retrying a register later...", + ) + _exit(0) elif data["result"] != "ok": logger.error( f"Received error from BunkerNet API while sending db request : {data['data']}, removing instance ID", diff --git a/src/common/core/bunkernet/jobs/bunkernet-register.py b/src/common/core/bunkernet/jobs/bunkernet-register.py index 4095a4ccb..741068133 100755 --- a/src/common/core/bunkernet/jobs/bunkernet-register.py +++ b/src/common/core/bunkernet/jobs/bunkernet-register.py @@ -66,14 +66,19 @@ try: "BunkerNet API is rate limiting us, trying again later...", ) _exit(0) + elif status == 403: + logger.warning( + "BunkerNet has banned this instance, retrying a register later...", + ) + _exit(0) elif status != 200: logger.error( f"Error {status} from BunkerNet API : {data['data']}", ) _exit(1) - elif data["result"] != "ok": + elif data.get("result", "ko") != "ok": logger.error( - f"Received error from BunkerNet API while sending register request : {data['data']}" + f"Received error from BunkerNet API while sending register request : {data.get('data', {})}" ) _exit(1) bunkernet_id = data["data"] @@ -98,15 +103,19 @@ try: "BunkerNet API is rate limiting us, trying again later...", ) retry = True + elif status == 403: + logger.warning( + "BunkerNet has banned this instance, retrying a register later...", + ) elif status == 401: logger.warning( "Instance ID is not registered, removing it and retrying a register later...", ) remove("/var/cache/bunkerweb/bunkernet/instance.id") _exit(2) - elif data["result"] != "ok": + elif data.get("result", "ko") != "ok": logger.error( - f"Received error from BunkerNet API while sending ping request : {data['data']}, removing instance ID", + f"Received error from BunkerNet API while sending ping request : {data.get('data', {})}, removing instance ID", ) retry = True if not retry: @@ -115,7 +124,7 @@ try: logger.warning("Waiting 1s and trying again ...") sleep(1) - if bunkernet_ping: + if bunkernet_ping and status != 403: logger.info("Connectivity with BunkerWeb is successful !") status = 1 if not isfile("/var/cache/bunkerweb/bunkernet/instance.id"): diff --git a/src/common/core/bunkernet/jobs/bunkernet.py b/src/common/core/bunkernet/jobs/bunkernet.py index eff3b6005..c8dc908d3 100644 --- a/src/common/core/bunkernet/jobs/bunkernet.py +++ b/src/common/core/bunkernet/jobs/bunkernet.py @@ -1,9 +1,12 @@ -import requests, traceback +from typing import Literal, Optional, Tuple, Union +import requests from os import getenv from os.path import exists -def request(method, url, _id=None): +def request( + method: Union[Literal["POST"], Literal["GET"]], url: str, _id: Optional[str] = None +) -> Tuple[bool, Optional[int], Union[str, dict]]: data = {"integration": get_integration(), "version": get_version()} headers = {"User-Agent": f"BunkerWeb/{get_version()}"} if _id is not None: @@ -19,11 +22,17 @@ def request(method, url, _id=None): status = resp.status_code if status == 429: return True, 429, "rate limited" - raw_data = resp.json() + elif status == 403: + return True, 403, "forbidden" + + raw_data: dict = resp.json() + assert "result" in raw_data assert "data" in raw_data + except requests.ReadTimeout: + return False, None, "request timed out" except Exception as e: - return False, None, traceback.format_exc() + return False, None, f"request failed: {e}" return True, status, raw_data diff --git a/src/common/core/errors/plugin.json b/src/common/core/errors/plugin.json index da6cc46bb..b4e3f976c 100644 --- a/src/common/core/errors/plugin.json +++ b/src/common/core/errors/plugin.json @@ -20,7 +20,7 @@ "help": "List of HTTP error code intercepted by Bunkerweb", "id": "intercepted-error-codes", "label": "Intercepted error codes", - "regex": "^.*$", + "regex": "^( *([1-5]\\d{2})(?!.*\\2) *)+$", "type": "text" } } diff --git a/src/common/core/misc/jobs/default-server-cert.py b/src/common/core/misc/jobs/default-server-cert.py new file mode 100644 index 000000000..abc4c51ce --- /dev/null +++ b/src/common/core/misc/jobs/default-server-cert.py @@ -0,0 +1,78 @@ +#!/usr/bin/python3 + +from os import getenv, makedirs +from os.path import isfile +from subprocess import DEVNULL, STDOUT, run +from sys import exit as sys_exit, path as sys_path +from traceback import format_exc + +sys_path.extend( + ( + "/usr/share/bunkerweb/deps/python", + "/usr/share/bunkerweb/utils", + ) +) + +from logger import setup_logger + +logger = setup_logger("DEFAULT-SERVER-CERT", getenv("LOG_LEVEL", "INFO")) +status = 0 + +try: + + # Check if we need to generate a self-signed default cert for non-SNI "clients" + need_default_cert = False + if getenv("MULTISITE", "no") == "yes": + for first_server in getenv("SERVER_NAME", "").split(" "): + for check_var in [ + "USE_CUSTOM_HTTPS", + "AUTO_LETS_ENCRYPT", + "GENERATE_SELF_SIGNED_SSL", + ]: + if ( + getenv(f"{first_server}_{check_var}", getenv(check_var, "no")) + == "yes" + ): + need_default_cert = True + break + if need_default_cert: + break + elif getenv("DISABLE_DEFAULT_SERVER", "no") == "yes" and ( + getenv("USE_CUSTOM_HTTPS", "no") == "yes" + or getenv("AUTO_LETS_ENCRYPT", "no") == "yes" + or getenv("GENERATE_SELF_SIGNED_SSL", "no") == "yes" + ): + need_default_cert = True + + # Generate the self-signed certificate + if need_default_cert: + makedirs("/var/cache/bunkerweb/default-server-cert", exist_ok=True) + if not isfile("/var/cache/bunkerweb/default-server-cert/cert.pem"): + cmd = "openssl req -nodes -x509 -newkey rsa:4096 -keyout /var/cache/bunkerweb/default-server-cert/cert.key -out /var/cache/bunkerweb/default-server-cert/cert.pem -days 3650".split( + " " + ) + cmd.extend(["-subj", "/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/"]) + proc = run(cmd, stdin=DEVNULL, stderr=STDOUT) + if proc.returncode != 0: + logger.error( + "Self-signed certificate generation failed for default server", + ) + status = 2 + else: + logger.info( + "Successfully generated self-signed certificate for default server", + ) + else: + logger.info( + "Skipping generation of self-signed certificate for default server (already present)", + ) + else: + logger.info( + "Skipping generation of self-signed certificate for default server (not needed)", + ) + +except: + status = 2 + logger.error(f"Exception while running default-server-cert.py :\n{format_exc()}") + +sys_exit(status) diff --git a/src/common/core/misc/plugin.json b/src/common/core/misc/plugin.json index 7d52a3d6a..d08e1ebab 100644 --- a/src/common/core/misc/plugin.json +++ b/src/common/core/misc/plugin.json @@ -159,5 +159,13 @@ "type": "select", "select": ["403", "444"] } - } + }, + "jobs": [ + { + "name": "default-server-cert", + "file": "default-server-cert.py", + "every": "once", + "reload": false + } + ] } diff --git a/src/linux/scripts/bunkerweb-ui.sh b/src/linux/scripts/bunkerweb-ui.sh index ebfeea4ee..2c488a335 100755 --- a/src/linux/scripts/bunkerweb-ui.sh +++ b/src/linux/scripts/bunkerweb-ui.sh @@ -6,8 +6,8 @@ export PYTHONPATH=/usr/share/bunkerweb/deps/python # Create the ui.env file if it doesn't exist if [ ! -f /etc/bunkerweb/ui.env ]; then echo "ADMIN_USERNAME=admin" > /etc/bunkerweb/ui.env - echo "ADMIN_PASSWORD=PasswordChanged" >> /etc/bunkerweb/ui.env - echo "ABSOLUTE_URI=" >> /etc/bunkerweb/ui.env + echo "ADMIN_PASSWORD=changeme" >> /etc/bunkerweb/ui.env + echo "ABSOLUTE_URI=http://mydomain.ext/mypath/" >> /etc/bunkerweb/ui.env fi # Function to start the UI @@ -18,7 +18,7 @@ start() { fi source /etc/bunkerweb/ui.env export $(cat /etc/bunkerweb/ui.env) - python3 -m gunicorn --bind=127.0.0.1:7000 --chdir /usr/share/bunkerweb/ui/ --workers=1 --threads=2 main:app & + python3 -m gunicorn --graceful-timeout=0 --bind=127.0.0.1:7000 --chdir /usr/share/bunkerweb/ui/ --workers=1 --threads=2 main:app & echo $! > /var/tmp/bunkerweb/ui.pid } diff --git a/src/scheduler/Dockerfile b/src/scheduler/Dockerfile index e67f8312e..ba7e7852c 100644 --- a/src/scheduler/Dockerfile +++ b/src/scheduler/Dockerfile @@ -64,7 +64,7 @@ RUN apk add --no-cache bash libgcc libstdc++ openssl && \ chmod 660 /usr/share/bunkerweb/INTEGRATION # Fix CVEs -RUN apk add "libssl1.1>=1.1.1q-r0" "libcrypto1.1>=1.1.1q-r0" "git>=2.32.3-r0" "libxml2>=2.9.14-r1" "expat>=2.5.0-r0" "git>=2.36.5-r0" +RUN apk add "libssl1.1>=1.1.1q-r0" "libcrypto1.1>=1.1.1q-r0" "libxml2>=2.9.14-r1" "expat>=2.5.0-r0" "git>=2.36.5-r0" VOLUME /data /etc/nginx diff --git a/src/scheduler/JobScheduler.py b/src/scheduler/JobScheduler.py index e4a166cf8..c5f2287b8 100644 --- a/src/scheduler/JobScheduler.py +++ b/src/scheduler/JobScheduler.py @@ -1,8 +1,8 @@ -from copy import deepcopy +from functools import partial from glob import glob from json import loads from logging import Logger -from os import environ, getenv +from os import cpu_count, environ, getenv from subprocess import DEVNULL, PIPE, STDOUT, run from threading import Lock, Thread from schedule import ( @@ -190,27 +190,34 @@ class JobScheduler(ApiCaller): return success def run_once(self): - ret = True threads = [] for plugin, jobs in self.__jobs.items(): + jobs_jobs = [] + for job in jobs: path = job["path"] name = job["name"] file = job["file"] - if job["name"].startswith("bunkernet"): - self.__job_wrapper(path, plugin, name, file) - else: - thread = Thread( - target=self.__job_wrapper, args=(path, plugin, name, file) - ) - threads.append(thread) + # Add job to the list of jobs to run in the order they are defined + jobs_jobs.append(partial(self.__job_wrapper, path, plugin, name, file)) - for thread in threads: - thread.start() + # Create a thread for each plugin + threads.append( + Thread( + target=lambda jobs_jobs: [job() for job in jobs_jobs], + args=(jobs_jobs,), + ) + ) - for thread in threads: - thread.join() + # Split the list of threads into sublists of the max cpu count + nbr_cpu = cpu_count() or 1 + for i in range(0, len(threads), nbr_cpu): + sublist = threads[i : i + nbr_cpu] + for t in sublist: + t.start() + for t in sublist: + t.join() ret = self.__job_success self.__job_success = True diff --git a/src/ui/Dockerfile b/src/ui/Dockerfile index 92377927a..d7bdbae61 100755 --- a/src/ui/Dockerfile +++ b/src/ui/Dockerfile @@ -50,7 +50,7 @@ RUN apk add --no-cache bash && \ chmod 660 /usr/share/bunkerweb/INTEGRATION # Fix CVEs -RUN apk add "libssl1.1>=1.1.1q-r0" "libcrypto1.1>=1.1.1q-r0" "git>=2.32.3-r0" "libxml2>=2.9.14-r1" "expat>=2.5.0-r0" +RUN apk add "libssl1.1>=1.1.1q-r0" "libcrypto1.1>=1.1.1q-r0" "libxml2>=2.9.14-r1" "expat>=2.5.0-r0" "git>=2.36.5-r0" VOLUME /data /etc/nginx diff --git a/src/ui/templates/services.html b/src/ui/templates/services.html index 2f77f356e..d8b38b02f 100644 --- a/src/ui/templates/services.html +++ b/src/ui/templates/services.html @@ -352,7 +352,7 @@ - {% if service["SERVER_NAME"]['method'] != "scheduler" %} + {% if service["SERVER_NAME"]['method'] == "ui" %}