# Docker Type of document: How-to guide Product: F5 WAF for NGINX --- This page describes how to install F5 WAF for NGINX using Docker. ## Before you begin To complete this guide, you will need the following prerequisites: - A [supported operating system](/waf/fundamentals/technical-specifications.md#supported-operating-systems). - [Docker](https://docs.docker.com/engine/install/) (with Docker Compose) installed and running. - Ensure you have an active F5 WAF for NGINX subscription (purchased or trial) and have downloaded the associated [SSL certificate, private key, and JWT license](#download-your-subscription-credentials) file from the MyF5 Customer Portal. JWT license is not needed when using NGINX Open Source. - [Docker registry credentials](#download-your-subscription-credentials) for private-registry.nginx.com, required to pull images for Multi-container and Hybrid configurations. You should read the [IP intelligence](/waf/policies/ip-intelligence.md) and [Secure traffic using mTLS](/waf/configure/secure-mtls.md) topics for additional set-up configuration if you want to use them immediately. **Note:** Security mechanisms like SELinux or AppArmor may potentially block necessary file access for the NGINX process and any component containers. For more information, view the [Configure SELinux](/waf/configure/selinux.md) topic. ## Default security policy and logging profile F5 WAF for NGINX uses built-in default security policy and logging profile after installation. To use custom policies or logging profiles, update your NGINX configuration file accordingly. ## Download your subscription credentials To download the necessary files for deploying F5 WAF for NGINX, follow these steps: 1. Log in to [MyF5](https://my.f5.com/manage/s/). 2. Go to **My Products & Plans > Subscriptions** to see your active subscriptions. 3. Find your NGINX subscription, and select the **Subscription ID** for details. 4. Download the following files: - **SSL Certificate** - **Private Key** - **JSON Web Token (JWT)** (required for NGINX Plus but not necessary for NGINX Open Source users) **Note:** The provided Dockerfile for NGINX Plus automatically handles placing the JWT license file in `/etc/nginx/` during image build. If you use a custom Dockerfile, you must ensure the JWT license is copied to this location. ## Docker deployment options There are three kinds of Docker deployments available: - Multi-container configuration - Hybrid configuration - Single container configuration The multi-container configuration is recommended if you are building a new system, and deploys the F5 for WAF module and its components in separate images, allowing for nuanced version management. The hybrid configuration is suitable if you want to add F5 WAF for NGINX to an existing virtual environment and wish to use Docker for the F5 WAF components instead of installing and configuring WAF packages as explained in the [Virtual machine or bare metal](/waf/install/virtual-environment.md) instructions. The single container configuration only supports NGINX Plus and requires a building a Docker image that encapsulates all parts of the system. This image will need to be rebuilt with each release. The steps you should follow on this page are dependent on your configuration type: after the shared steps, links will guide you to the next appropriate section. ## Configure Docker for the F5 Container Registry You will need Docker registry credentials to access private-registry.nginx.com for the Multi-container or Hybrid deployment options. Create a directory and copy your certificate and key to this directory: ```shell mkdir -p /etc/docker/certs.d/private-registry.nginx.com cp /etc/docker/certs.d/private-registry.nginx.com/client.cert cp /etc/docker/certs.d/private-registry.nginx.com/client.key ``` You should now move to the section based on your configuration type: - [Multi-container configuration](#multi-container-configuration) - [Hybrid configuration](#hybrid-configuration) - [Single container configuration](#single-container-configuration) ## Multi-container configuration ### Create configuration files Copy or move your subscription files into a new folder. In the same folder, create three files: - _nginx.conf_ - An NGINX configuration file with F5 WAF for NGINX enabled - _entrypoint.sh_ - A Docker startup script which spins up all F5 WAF for NGINX processes, requiring executable permissions - _custom_log_format.json_ - An optional user-defined security log format file **Note:** If you are not using `custom_log_format.json`, you should remove any references to it from your nginx.conf and entrypoint.sh files. Here are examples of the file contents: #### nginx.conf ```nginx {hl_lines=[4, 26, 27, 28]} user nginx; worker_processes auto; load_module modules/ngx_http_app_protect_module.so; error_log /var/log/nginx/error.log warn; events { worker_connections 10240; } http { include /etc/nginx/mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; upstream app_backend_com { server 192.168.0.1:8000; server 192.168.0.1:8001; } server { listen 80; server_name app.example.com; app_protect_enable on; app_protect_security_log_enable on; app_protect_security_log "/etc/nginx/custom_log_format.json" syslog:server=127.0.0.1:514; location / { client_max_body_size 0; default_type text/html; # set your backend here proxy_pass http://app_backend_com; proxy_set_header Host $host; } } } ``` #### entrypoint.sh ```shell #!/bin/sh /bin/su -s /bin/sh -c "/usr/share/ts/bin/bd-socket-plugin tmm_count 4 proc_cpuinfo_cpu_mhz 2000000 total_xml_memory 307200000 total_umu_max_size 3129344 sys_max_account_id 1024 no_static_config 2>&1 >> /var/log/app_protect/bd-socket-plugin.log &" nginx /usr/sbin/nginx -g 'daemon off;' # Optional line for the IP intelligence feature /opt/app_protect/bin/iprepd /etc/app_protect/tools/iprepd.cfg > ipi.log 2>&1 & ``` #### custom_log_format.json ```json { "filter": { "request_type": "all" }, "content": { "format": "splunk", "max_request_size": "any", "max_message_size": "10k" } } ``` ### Create a Dockerfile In the same folder as your credential and configuration files, create a _Dockerfile_ based on your [desired operating system](/waf/fundamentals/technical-specifications.md#supported-operating-systems) image using an example from the following sections. Alternatively, you may want make your own image based on a Dockerfile using the official NGINX image: #### Dockerfile based on official image This example uses NGINX Open Source as a base: it requires NGINX to be installed as a package from the official repository, instead of being compiled from source. ```dockerfile # syntax=docker/dockerfile:1 # Base image FROM nginx:1.25.5-bookworm # Install F5 WAF for NGINX v5 module RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ --mount=type=secret,id=nginx-key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ apt-get update \ && apt-get install --no-install-recommends --no-install-suggests -y \ apt-transport-https \ lsb-release \ ca-certificates \ wget \ gnupg \ && wget https://cs.nginx.com/static/keys/nginx_signing.key \ && gpg --no-default-keyring --keyring gnupg-ring:/etc/apt/trusted.gpg.d/nginx.gpg \ --import nginx_signing.key \ && chmod 644 /etc/apt/trusted.gpg.d/nginx.gpg \ && printf "deb https://pkgs.nginx.com/app-protect-x-oss/debian `lsb_release -cs` nginx-plus\n" | \ tee /etc/apt/sources.list.d/nginx-app-protect.list \ && wget -P /etc/apt/apt.conf.d https://cs.nginx.com/static/files/90pkgs-nginx \ && apt-get update \ && apt-get install --no-install-recommends --no-install-suggests -y nginx=1.25.5-1~bookworm app-protect-module-oss \ && apt-get remove --purge --auto-remove -y apt-transport-https lsb-release gnupg wget \ && rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/nginx-app-protect.list ``` **Note:** If you are not using using `custom_log_format.json` or the IP intelligence feature, you should remove any references to them from your Dockerfile. #### Alpine Linux #### NGINX Open Source ```dockerfile # syntax=docker/dockerfile:1 # Supported OS_VER's are 3.22 ARG OS_VER="3.22" # Base image FROM alpine:${OS_VER} # Install NGINX OSS and F5 WAF for NGINX v5 module RUN --mount=type=secret,id=nginx-crt,dst=/etc/apk/cert.pem,mode=0644 \ --mount=type=secret,id=nginx-key,dst=/etc/apk/cert.key,mode=0644 \ apk add openssl curl ca-certificates \ && printf "%s%s%s%s\n" \ "http://nginx.org/packages/mainline/alpine/v" \ `egrep -o '^[0-9]+\.[0-9]+' /etc/alpine-release` \ "/main" \ | tee -a /etc/apk/repositories \ && wget -O /etc/apk/keys/nginx_signing.rsa.pub https://cs.nginx.com/static/keys/nginx_signing.rsa.pub \ && printf "https://pkgs.nginx.com/app-protect-x-oss/alpine/v`egrep -o '^[0-9]+\.[0-9]+' /etc/alpine-release`/main\n" | \ tee -a /etc/apk/repositories \ && apk update \ && apk add app-protect-module-oss \ && ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log \ && rm -rf /var/cache/apk/* # Expose port EXPOSE 80 # Define stop signal STOPSIGNAL SIGQUIT # Set default command CMD ["nginx", "-g", "daemon off;"] ``` #### NGINX Plus ```dockerfile # syntax=docker/dockerfile:1 # Supported OS_VER's are 3.22 ARG OS_VER="3.22" # Base image FROM alpine:${OS_VER} # Install NGINX Plus and F5 WAF for NGINX v5 module RUN --mount=type=secret,id=nginx-crt,dst=/etc/apk/cert.pem,mode=0644 \ --mount=type=secret,id=nginx-key,dst=/etc/apk/cert.key,mode=0644 \ wget -O /etc/apk/keys/nginx_signing.rsa.pub https://cs.nginx.com/static/keys/nginx_signing.rsa.pub \ && printf "https://pkgs.nginx.com/plus/alpine/v`egrep -o '^[0-9]+\.[0-9]+' /etc/alpine-release`/main\n" | \ tee -a /etc/apk/repositories \ && printf "https://pkgs.nginx.com/app-protect-x-plus/alpine/v`egrep -o '^[0-9]+\.[0-9]+' /etc/alpine-release`/main\n" | \ tee -a /etc/apk/repositories \ && apk update \ && apk add app-protect-module-plus \ && ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log \ && rm -rf /var/cache/apk/* # Securely copy the JWT license: RUN --mount=type=secret,id=license-jwt,dst=license.jwt \ cp license.jwt /etc/nginx/license.jwt # Expose port EXPOSE 80 # Define stop signal STOPSIGNAL SIGQUIT # Set default command CMD ["nginx", "-g", "daemon off;"] ``` #### Amazon Linux #### NGINX Open Source ```dockerfile # syntax=docker/dockerfile:1 # Base image FROM amazonlinux:2023 # Install NGINX OSS and F5 WAF for NGINX WAF v5 module RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ --mount=type=secret,id=nginx-key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ yum -y install wget ca-certificates shadow-utils yum-utils \ && echo "[nginx-mainline]" > /etc/yum.repos.d/nginx.repo \ && echo "name=nginx mainline repo" >> /etc/yum.repos.d/nginx.repo \ && echo "baseurl=http://nginx.org/packages/mainline/amzn/2023/\$basearch/" >> /etc/yum.repos.d/nginx.repo \ && echo "gpgcheck=1" >> /etc/yum.repos.d/nginx.repo \ && echo "enabled=1" >> /etc/yum.repos.d/nginx.repo \ && echo "gpgkey=https://nginx.org/keys/nginx_signing.key" >> /etc/yum.repos.d/nginx.repo \ && echo "module_hotfixes=true" >> /etc/yum.repos.d/nginx.repo \ && echo "priority=9" >> /etc/yum.repos.d/nginx.repo \ && echo "[app-protect-x-oss]" > /etc/yum.repos.d/app-protect-oss.repo \ && echo "name=nginx-app-protect repo" >> /etc/yum.repos.d/app-protect-oss.repo \ && echo "baseurl=https://pkgs.nginx.com/app-protect-x-oss/amzn/2023/\$basearch/" >> /etc/yum.repos.d/app-protect-oss.repo \ && echo "sslclientcert=/etc/ssl/nginx/nginx-repo.crt" >> /etc/yum.repos.d/app-protect-oss.repo \ && echo "sslclientkey=/etc/ssl/nginx/nginx-repo.key" >> /etc/yum.repos.d/app-protect-oss.repo \ && echo "gpgcheck=0" >> /etc/yum.repos.d/app-protect-oss.repo \ && echo "enabled=1" >> /etc/yum.repos.d/app-protect-oss.repo \ && yum -y install app-protect-module-oss \ && yum clean all \ && rm -rf /var/cache/yum \ && ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log # Expose port EXPOSE 80 # Define stop signal STOPSIGNAL SIGQUIT # Set default command CMD ["nginx", "-g", "daemon off;"] ``` #### NGINX Plus ```dockerfile # syntax=docker/dockerfile:1 # Base image FROM amazonlinux:2023 # Install NGINX Plus and F5 WAF for NGINX v5 module RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ --mount=type=secret,id=nginx-key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ yum -y install wget ca-certificates shadow-utils \ && wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/plus-amazonlinux2023.repo \ && echo "[app-protect-x-plus]" > /etc/yum.repos.d/app-protect-plus.repo \ && echo "name=nginx-app-protect repo" >> /etc/yum.repos.d/app-protect-plus.repo \ && echo "baseurl=https://pkgs.nginx.com/app-protect-x-plus/amzn/2023/\$basearch/" >> /etc/yum.repos.d/app-protect-plus.repo \ && echo "sslclientcert=/etc/ssl/nginx/nginx-repo.crt" >> /etc/yum.repos.d/app-protect-plus.repo \ && echo "sslclientkey=/etc/ssl/nginx/nginx-repo.key" >> /etc/yum.repos.d/app-protect-plus.repo \ && echo "gpgcheck=0" >> /etc/yum.repos.d/app-protect-plus.repo \ && echo "enabled=1" >> /etc/yum.repos.d/app-protect-plus.repo \ && yum -y install app-protect-module-plus \ && yum clean all \ && rm -rf /var/cache/yum \ && ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log # Securely copy the JWT license: RUN --mount=type=secret,id=license-jwt,dst=license.jwt \ cp license.jwt /etc/nginx/license.jwt # Expose port EXPOSE 80 # Define stop signal STOPSIGNAL SIGQUIT # Set default command CMD ["nginx", "-g", "daemon off;"] ``` #### Debian #### NGINX Open Source ```dockerfile # syntax=docker/dockerfile:1 # Supported OS_CODENAME's are: bullseye/bookworm ARG OS_CODENAME=bookworm # Base image FROM debian:${OS_CODENAME} # Install NGINX OSS and F5 WAF for NGINX v5 module RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ --mount=type=secret,id=nginx-key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ apt-get update \ && apt-get install -y \ apt-transport-https \ lsb-release \ ca-certificates \ wget \ gnupg2 \ debian-archive-keyring \ && wget -qO - https://nginx.org/keys/nginx_signing.key | gpg --dearmor | \ tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null \ && gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg \ && printf "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \ http://nginx.org/packages/mainline/debian `lsb_release -cs` nginx\n" | \ tee /etc/apt/sources.list.d/nginx.list \ && wget -qO - https://cs.nginx.com/static/keys/nginx_signing.key | gpg --dearmor | \ tee /usr/share/keyrings/nginx-static-archive-keyring.gpg >/dev/null \ && gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-static-archive-keyring.gpg \ && printf "deb [signed-by=/usr/share/keyrings/nginx-static-archive-keyring.gpg] \ https://pkgs.nginx.com/app-protect-x-oss/debian `lsb_release -cs` nginx-plus\n" | \ tee /etc/apt/sources.list.d/nginx-app-protect.list \ && wget -P /etc/apt/apt.conf.d https://cs.nginx.com/static/files/90pkgs-nginx \ && apt-get update \ && DEBIAN_FRONTEND="noninteractive" apt-get install -y nginx=1.25.5-1~`lsb_release -cs` app-protect-module-oss \ && ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* # Expose port EXPOSE 80 # Define stop signal STOPSIGNAL SIGQUIT # Set default command CMD ["nginx", "-g", "daemon off;"] ``` #### NGINX Plus ```dockerfile # syntax=docker/dockerfile:1 # Supported OS_CODENAME's are: bullseye/bookworm ARG OS_CODENAME=bookworm # Base image FROM debian:${OS_CODENAME} # Install NGINX Plus and F5 WAF for NGINX v5 module RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ --mount=type=secret,id=nginx-key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ apt-get update \ && apt-get install -y \ apt-transport-https \ lsb-release \ ca-certificates \ wget \ gnupg2 \ debian-archive-keyring \ && wget -qO - https://cs.nginx.com/static/keys/nginx_signing.key | \ gpg --dearmor | tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null \ && gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg \ && printf "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \ https://pkgs.nginx.com/plus/debian `lsb_release -cs` nginx-plus\n" | \ tee /etc/apt/sources.list.d/nginx-plus.list \ && printf "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \ https://pkgs.nginx.com/app-protect-x-plus/debian `lsb_release -cs` nginx-plus\n" | \ tee /etc/apt/sources.list.d/nginx-app-protect.list \ && wget -P /etc/apt/apt.conf.d https://cs.nginx.com/static/files/90pkgs-nginx \ && apt-get update \ && DEBIAN_FRONTEND="noninteractive" apt-get install -y app-protect-module-plus \ && ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* # Securely copy the JWT license: RUN --mount=type=secret,id=license-jwt,dst=license.jwt \ cp license.jwt /etc/nginx/license.jwt # Expose port EXPOSE 80 # Define stop signal STOPSIGNAL SIGQUIT # Set default command CMD ["nginx", "-g", "daemon off;"] ``` #### Oracle Linux #### NGINX Open Source ```dockerfile # syntax=docker/dockerfile:1 # Base image FROM oraclelinux:8 # Install NGINX OSS and F5 WAF for NGINX v5 module RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ --mount=type=secret,id=nginx-key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ dnf -y install wget ca-certificates yum-utils \ && echo "[nginx-mainline]" > /etc/yum.repos.d/nginx.repo \ && echo "name=nginx mainline repo" >> /etc/yum.repos.d/nginx.repo \ && echo "baseurl=http://nginx.org/packages/mainline/centos/\$releasever/\$basearch/" >> /etc/yum.repos.d/nginx.repo \ && echo "gpgcheck=1" >> /etc/yum.repos.d/nginx.repo \ && echo "enabled=1" >> /etc/yum.repos.d/nginx.repo \ && echo "gpgkey=https://nginx.org/keys/nginx_signing.key" >> /etc/yum.repos.d/nginx.repo \ && echo "module_hotfixes=true" >> /etc/yum.repos.d/nginx.repo \ && echo "[app-protect-x-oss]" > /etc/yum.repos.d/app-protect-8-x-oss.repo \ && echo "name=nginx-app-protect repo" >> /etc/yum.repos.d/app-protect-8-x-oss.repo \ && echo "baseurl=https://pkgs.nginx.com/app-protect-x-oss/centos/8/\$basearch/" >> /etc/yum.repos.d/app-protect-8-x-oss.repo \ && echo "sslclientcert=/etc/ssl/nginx/nginx-repo.crt" >> /etc/yum.repos.d/app-protect-8-x-oss.repo \ && echo "sslclientkey=/etc/ssl/nginx/nginx-repo.key" >> /etc/yum.repos.d/app-protect-8-x-oss.repo \ && echo "gpgcheck=0" >> /etc/yum.repos.d/app-protect-8-x-oss.repo \ && echo "enabled=1" >> /etc/yum.repos.d/app-protect-8-x-oss.repo \ && dnf clean all \ && dnf -y install app-protect-module-oss \ && dnf clean all \ && rm -rf /var/cache/dnf \ && ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log # Expose port EXPOSE 80 # Define stop signal STOPSIGNAL SIGQUIT # Set default command CMD ["nginx", "-g", "daemon off;"] ``` #### NGINX Plus ```dockerfile # syntax=docker/dockerfile:1 # Base image FROM oraclelinux:8 # Install NGINX Plus and F5 WAF for NGINX v5 module RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ --mount=type=secret,id=nginx-key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ dnf -y install wget ca-certificates yum-utils \ && wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/nginx-plus-8.repo \ && echo "[app-protect-x-plus]" > /etc/yum.repos.d/app-protect-8-x-plus.repo \ && echo "name=nginx-app-protect repo" >> /etc/yum.repos.d/app-protect-8-x-plus.repo \ && echo "baseurl=https://pkgs.nginx.com/app-protect-x-plus/centos/8/\$basearch/" >> /etc/yum.repos.d/app-protect-8-x-plus.repo \ && echo "sslclientcert=/etc/ssl/nginx/nginx-repo.crt" >> /etc/yum.repos.d/app-protect-8-x-plus.repo \ && echo "sslclientkey=/etc/ssl/nginx/nginx-repo.key" >> /etc/yum.repos.d/app-protect-8-x-plus.repo \ && echo "gpgcheck=0" >> /etc/yum.repos.d/app-protect-8-x-plus.repo \ && echo "enabled=1" >> /etc/yum.repos.d/app-protect-8-x-plus.repo \ && dnf clean all \ && dnf -y install app-protect-module-plus \ && dnf clean all \ && rm -rf /var/cache/dnf \ && ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log # Securely copy the JWT license: RUN --mount=type=secret,id=license-jwt,dst=license.jwt \ cp license.jwt /etc/nginx/license.jwt # Expose port EXPOSE 80 # Define stop signal STOPSIGNAL SIGQUIT # Set default command CMD ["nginx", "-g", "daemon off;"] ``` #### Ubuntu #### NGINX Open Source ```dockerfile # syntax=docker/dockerfile:1 # Supported OS_CODENAME's are: focal/jammy ARG OS_CODENAME=jammy # Base image FROM ubuntu:${OS_CODENAME} # Install NGINX OSS and F5 WAF for NGINX v5 module RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ --mount=type=secret,id=nginx-key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ apt-get update \ && apt-get install -y \ apt-transport-https \ lsb-release \ ca-certificates \ wget \ gnupg2 \ ubuntu-keyring \ && wget -qO - https://nginx.org/keys/nginx_signing.key | gpg --dearmor | \ tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null \ && gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg \ && printf "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \ http://nginx.org/packages/mainline/ubuntu `lsb_release -cs` nginx\n" | \ tee /etc/apt/sources.list.d/nginx.list \ && wget -qO - https://cs.nginx.com/static/keys/nginx_signing.key | gpg --dearmor | \ tee /usr/share/keyrings/nginx-static-archive-keyring.gpg >/dev/null \ && gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-static-archive-keyring.gpg \ && printf "deb [signed-by=/usr/share/keyrings/nginx-static-archive-keyring.gpg] \ https://pkgs.nginx.com/app-protect-x-oss/ubuntu `lsb_release -cs` nginx-plus\n" | \ tee /etc/apt/sources.list.d/nginx-app-protect.list \ && wget -P /etc/apt/apt.conf.d https://cs.nginx.com/static/files/90pkgs-nginx \ && apt-get update \ && DEBIAN_FRONTEND="noninteractive" apt-get install -y nginx=1.25.5-1~`lsb_release -cs` app-protect-module-oss \ && ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* # Expose port EXPOSE 80 # Define stop signal STOPSIGNAL SIGQUIT # Set default command CMD ["nginx", "-g", "daemon off;"] ``` #### NGINX Plus ```dockerfile # syntax=docker/dockerfile:1 # Supported OS_CODENAME's are: focal/jammy ARG OS_CODENAME=jammy # Base image FROM ubuntu:${OS_CODENAME} # Install NGINX Plus and F5 WAF for NGINX v5 module RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ --mount=type=secret,id=nginx-key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ apt-get update \ && apt-get install -y \ apt-transport-https \ lsb-release \ ca-certificates \ wget \ gnupg2 \ ubuntu-keyring \ && wget -qO - https://cs.nginx.com/static/keys/nginx_signing.key | \ gpg --dearmor | tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null \ && gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg \ && printf "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \ https://pkgs.nginx.com/plus/ubuntu `lsb_release -cs` nginx-plus\n" | \ tee /etc/apt/sources.list.d/nginx-plus.list \ && printf "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \ https://pkgs.nginx.com/app-protect-x-plus/ubuntu `lsb_release -cs` nginx-plus\n" | \ tee /etc/apt/sources.list.d/nginx-app-protect.list \ && wget -P /etc/apt/apt.conf.d https://cs.nginx.com/static/files/90pkgs-nginx \ && apt-get update \ && DEBIAN_FRONTEND="noninteractive" apt-get install -y app-protect-module-plus \ && ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* # Securely copy the JWT license: RUN --mount=type=secret,id=license-jwt,dst=license.jwt \ cp license.jwt /etc/nginx/license.jwt # Expose port EXPOSE 80 # Define stop signal STOPSIGNAL SIGQUIT # Set default command CMD ["nginx", "-g", "daemon off;"] ``` #### RHEL 8 #### NGINX Open Source ```dockerfile # syntax=docker/dockerfile:1 # Supported UBI_VERSION's are 7/8/9 ARG UBI_VERSION=8 # Base Image FROM registry.access.redhat.com/ubi${UBI_VERSION}/ubi # Define the ARG again after FROM to use it in this stage ARG UBI_VERSION # Install NGINX OSS and F5 WAF for NGINX v5 module RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ --mount=type=secret,id=nginx-key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ PKG_MANAGER=dnf; \ if [ "${UBI_VERSION}" = "7" ]; then \ PKG_MANAGER=yum; \ fi \ && $PKG_MANAGER -y install wget ca-certificates yum-utils \ && wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/dependencies.repo \ && echo "[nginx-mainline]" > /etc/yum.repos.d/nginx.repo \ && echo "name=nginx mainline repo" >> /etc/yum.repos.d/nginx.repo \ && echo "baseurl=http://nginx.org/packages/mainline/centos/\$releasever/\$basearch/" >> /etc/yum.repos.d/nginx.repo \ && echo "gpgcheck=1" >> /etc/yum.repos.d/nginx.repo \ && echo "enabled=1" >> /etc/yum.repos.d/nginx.repo \ && echo "gpgkey=https://nginx.org/keys/nginx_signing.key" >> /etc/yum.repos.d/nginx.repo \ && echo "module_hotfixes=true" >> /etc/yum.repos.d/nginx.repo \ && echo "[app-protect-x-oss]" > /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "name=nginx-app-protect repo" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "baseurl=https://pkgs.nginx.com/app-protect-x-oss/centos/${UBI_VERSION}/\$basearch/" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "sslclientcert=/etc/ssl/nginx/nginx-repo.crt" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "sslclientkey=/etc/ssl/nginx/nginx-repo.key" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "gpgcheck=0" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "enabled=1" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && $PKG_MANAGER clean all \ && $PKG_MANAGER install -y app-protect-module-oss \ && $PKG_MANAGER clean all \ && rm -rf /var/cache/$PKG_MANAGER \ && ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log # Expose port EXPOSE 80 # Define stop signal STOPSIGNAL SIGQUIT # Set default command CMD ["nginx", "-g", "daemon off;"] ``` #### NGINX Plus ```dockerfile # syntax=docker/dockerfile:1 # Supported UBI_VERSION's are 7/8/9 ARG UBI_VERSION=8 # Base Image FROM registry.access.redhat.com/ubi${UBI_VERSION}/ubi # Define the ARG again after FROM to use it in this stage ARG UBI_VERSION # Install NGINX Plus and F5 WAF for NGINX v5 module RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ --mount=type=secret,id=nginx-key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ PKG_MANAGER=dnf; \ if [ "${UBI_VERSION}" = "7" ]; then \ PKG_MANAGER=yum; \ NGINX_PLUS_REPO="nginx-plus-7.4.repo"; \ elif [ "${UBI_VERSION}" = "9" ]; then \ NGINX_PLUS_REPO="plus-${UBI_VERSION}.repo"; \ else \ NGINX_PLUS_REPO="nginx-plus-${UBI_VERSION}.repo"; \ fi \ && $PKG_MANAGER -y install wget ca-certificates \ && wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/dependencies.repo \ && wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/${NGINX_PLUS_REPO} \ && echo "[app-protect-x-plus]" > /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "name=nginx-app-protect repo" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "baseurl=https://pkgs.nginx.com/app-protect-x-plus/centos/${UBI_VERSION}/\$basearch/" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "sslclientcert=/etc/ssl/nginx/nginx-repo.crt" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "sslclientkey=/etc/ssl/nginx/nginx-repo.key" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "gpgcheck=0" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "enabled=1" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && $PKG_MANAGER clean all \ && $PKG_MANAGER install -y app-protect-module-plus \ && $PKG_MANAGER clean all \ && rm -rf /var/cache/$PKG_MANAGER \ && ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log # Securely copy the JWT license: RUN --mount=type=secret,id=license-jwt,dst=license.jwt \ cp license.jwt /etc/nginx/license.jwt # Expose port EXPOSE 80 # Define stop signal STOPSIGNAL SIGQUIT # Set default command CMD ["nginx", "-g", "daemon off;"] ``` #### RHEL 9 #### NGINX Open Source ```dockerfile # syntax=docker/dockerfile:1 # Supported UBI_VERSION's are 7/8/9 ARG UBI_VERSION=8 # Base Image FROM registry.access.redhat.com/ubi${UBI_VERSION}/ubi # Define the ARG again after FROM to use it in this stage ARG UBI_VERSION # Install NGINX OSS and F5 WAF for NGINX v5 module RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ --mount=type=secret,id=nginx-key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ PKG_MANAGER=dnf; \ if [ "${UBI_VERSION}" = "7" ]; then \ PKG_MANAGER=yum; \ fi \ && $PKG_MANAGER -y install wget ca-certificates yum-utils \ && wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/dependencies.repo \ && echo "[nginx-mainline]" > /etc/yum.repos.d/nginx.repo \ && echo "name=nginx mainline repo" >> /etc/yum.repos.d/nginx.repo \ && echo "baseurl=http://nginx.org/packages/mainline/centos/\$releasever/\$basearch/" >> /etc/yum.repos.d/nginx.repo \ && echo "gpgcheck=1" >> /etc/yum.repos.d/nginx.repo \ && echo "enabled=1" >> /etc/yum.repos.d/nginx.repo \ && echo "gpgkey=https://nginx.org/keys/nginx_signing.key" >> /etc/yum.repos.d/nginx.repo \ && echo "module_hotfixes=true" >> /etc/yum.repos.d/nginx.repo \ && echo "[app-protect-x-oss]" > /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "name=nginx-app-protect repo" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "baseurl=https://pkgs.nginx.com/app-protect-x-oss/centos/${UBI_VERSION}/\$basearch/" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "sslclientcert=/etc/ssl/nginx/nginx-repo.crt" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "sslclientkey=/etc/ssl/nginx/nginx-repo.key" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "gpgcheck=0" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "enabled=1" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && $PKG_MANAGER clean all \ && $PKG_MANAGER install -y app-protect-module-oss \ && $PKG_MANAGER clean all \ && rm -rf /var/cache/$PKG_MANAGER \ && ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log # Expose port EXPOSE 80 # Define stop signal STOPSIGNAL SIGQUIT # Set default command CMD ["nginx", "-g", "daemon off;"] ``` #### NGINX Plus ```dockerfile # syntax=docker/dockerfile:1 # Base Image FROM rockylinux:9 # Install NGINX Plus and F5 WAF for NGINX v5 module RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ --mount=type=secret,id=nginx-key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ dnf -y install wget ca-certificates \ && wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/dependencies.repo \ && wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/${NGINX_PLUS_REPO} \ && echo "[app-protect-x-plus]" > /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "name=nginx-app-protect repo" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "baseurl=https://pkgs.nginx.com/app-protect-x-plus/centos/${UBI_VERSION}/\$basearch/" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "sslclientcert=/etc/ssl/nginx/nginx-repo.crt" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "sslclientkey=/etc/ssl/nginx/nginx-repo.key" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "gpgcheck=0" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "enabled=1" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && dnf clean all \ && dnf install -y app-protect-module-plus \ && dnf clean all \ && rm -rf /var/cache/dnf \ && ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log # Securely copy the JWT license: RUN --mount=type=secret,id=license-jwt,dst=license.jwt \ cp license.jwt /etc/nginx/license.jwt # Expose port EXPOSE 80 # Define stop signal STOPSIGNAL SIGQUIT # Set default command CMD ["nginx", "-g", "daemon off;"] ``` #### Rocky Linux 9 #### NGINX Open Source ```dockerfile # syntax=docker/dockerfile:1 # Base Image FROM rockylinux:9 # Install NGINX OSS and F5 WAF for NGINX v5 module RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ --mount=type=secret,id=nginx-key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ dnf -y install wget ca-certificates yum-utils \ && wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/dependencies.repo \ && echo "[nginx-mainline]" > /etc/yum.repos.d/nginx.repo \ && echo "name=nginx mainline repo" >> /etc/yum.repos.d/nginx.repo \ && echo "baseurl=http://nginx.org/packages/mainline/centos/\$releasever/\$basearch/" >> /etc/yum.repos.d/nginx.repo \ && echo "gpgcheck=1" >> /etc/yum.repos.d/nginx.repo \ && echo "enabled=1" >> /etc/yum.repos.d/nginx.repo \ && echo "gpgkey=https://nginx.org/keys/nginx_signing.key" >> /etc/yum.repos.d/nginx.repo \ && echo "module_hotfixes=true" >> /etc/yum.repos.d/nginx.repo \ && echo "[app-protect-x-oss]" > /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "name=nginx-app-protect repo" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "baseurl=https://pkgs.nginx.com/app-protect-x-oss/centos/${UBI_VERSION}/\$basearch/" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "sslclientcert=/etc/ssl/nginx/nginx-repo.crt" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "sslclientkey=/etc/ssl/nginx/nginx-repo.key" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "gpgcheck=0" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "enabled=1" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && dnf clean all \ && dnf install -y app-protect-module-oss \ && dnf clean all \ && rm -rf /var/cache/dnf \ && ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log # Expose port EXPOSE 80 # Define stop signal STOPSIGNAL SIGQUIT # Set default command CMD ["nginx", "-g", "daemon off;"] ``` #### NGINX Plus ```dockerfile # syntax=docker/dockerfile:1 # Base Image FROM rockylinux:9 # Install NGINX Plus and F5 WAF for NGINX v5 module RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ --mount=type=secret,id=nginx-key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ dnf -y install wget ca-certificates \ && wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/dependencies.repo \ && wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/${NGINX_PLUS_REPO} \ && echo "[app-protect-x-plus]" > /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "name=nginx-app-protect repo" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "baseurl=https://pkgs.nginx.com/app-protect-x-plus/centos/${UBI_VERSION}/\$basearch/" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "sslclientcert=/etc/ssl/nginx/nginx-repo.crt" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "sslclientkey=/etc/ssl/nginx/nginx-repo.key" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "gpgcheck=0" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "enabled=1" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && dnf clean all \ && dnf install -y app-protect-module-plus \ && dnf clean all \ && rm -rf /var/cache/dnf \ && ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log # Securely copy the JWT license: RUN --mount=type=secret,id=license-jwt,dst=license.jwt \ cp license.jwt /etc/nginx/license.jwt # Expose port EXPOSE 80 # Define stop signal STOPSIGNAL SIGQUIT # Set default command CMD ["nginx", "-g", "daemon off;"] ``` ### Build the Docker image Your folder should contain the following files: - _nginx-repo.crt_ - _nginx-repo.key_ - _license.jwt_ - _nginx.conf_ - _entrypoint.sh_ - _Dockerfile_ - _custom_log_format.json_ To build an image, use the following command for a system that is not RHEL-based, replacing `` as appropriate: ```shell sudo docker build --no-cache --platform linux/amd64 --secret id=nginx-crt,src=nginx-repo.crt --secret id=nginx-key,src=nginx-repo.key --secret id=license-jwt,src=license.jwt -t . ``` A RHEL-based system would use the following command instead: ```shell podman build --no-cache --secret id=nginx-crt,src=nginx-repo.crt --secret id=nginx-key,src=nginx-repo.key --secret id=license-jwt,src=license.jwt -t . ``` **Note:** The `--no-cache` option is used to ensure the image is built from scratch, installing the latest versions of NGINX Plus and F5 WAF for NGINX. Verify that your image has been created using the `docker images` command: ```shell docker images ``` Create a container based on this image, replacing as appropriate: ```shell docker run --name -p 80:80 -d ``` Verify the new container is running using the `docker ps` command: ```shell docker ps ``` ### Update configuration files Once you have installed F5 WAF for NGINX, you must load it as a module in the main context of your NGINX configuration. ```nginx load_module modules/ngx_http_app_protect_module.so; ``` The Enforcer address must be added at the _http_ context: ```nginx app_protect_enforcer_address : ``` And finally, F5 WAF for NGINX can enabled on a _http_, _server_ or _location_ context: ```nginx app_protect_enable on; ``` **Note:** You should only enable F5 WAF for NGINX on _proxy_pass_ and _grpc_pass_ locations. Here are two examples of how these additions could look in configuration: some of them may already exist from when you created the files. #### nginx.conf The default path for this file is `/etc/nginx/nginx.conf`. ```nginx {hl_lines=[5, 33]} user nginx; worker_processes auto; # F5 WAF for NGINX load_module modules/ngx_http_app_protect_module.so; error_log /var/log/nginx/error.log notice; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; keepalive_timeout 65; #gzip on; # F5 WAF for NGINX app_protect_enforcer_address 127.0.0.1:50000; include /etc/nginx/conf.d/*.conf; } ``` #### default.conf The default path for this file is `/etc/nginx/conf.d/default.conf`. ```nginx {hl_lines=[10]} server { listen 80; server_name domain.com; location / { # F5 WAF for NGINX app_protect_enable on; client_max_body_size 0; default_type text/html; proxy_pass http://127.0.0.1:8080/; } } server { listen 8080; server_name localhost; location / { root /usr/share/nginx/html; index index.html index.htm; } # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } } ``` Once you have updated your configuration files, you can reload NGINX to apply the changes. You have two options depending on your environment: - `nginx -s reload` - `sudo systemctl reload nginx` ### Configure Docker First, create new directories for the services: ```shell sudo mkdir -p /opt/app_protect/config /opt/app_protect/bd_config ``` Then assign new owners, with `101:101` as the default UID/GID ```shell sudo chown -R 101:101 /opt/app_protect/ ``` #### Download Docker images [Access to NGINX repo private-registry.nginx.com](/waf/install/docker.md#configure-docker-for-the-f5-container-registry) is needed to pull the following container images Download the `waf-enforcer` and `waf-config-mgr` images. Replace `5.2.0` with the release version you are deploying. ```shell docker pull private-registry.nginx.com/nap/waf-enforcer:5.2.0 docker pull private-registry.nginx.com/nap/waf-config-mgr:5.2.0 ``` #### Create and run a Docker Compose file Create a _docker-compose.yml_ file with the following contents in your host environment, replacing image tags as appropriate: ```yaml services: nginx: container_name: nginx image: nginx-app-protect-5 volumes: - /opt/app_protect/bd_config:/opt/app_protect/bd_config - /opt/app_protect/config:/opt/app_protect/config - /etc/app_protect/conf:/etc/app_protect/conf - /conf/nginx.conf:/etc/nginx/nginx.conf - /conf/default.conf:/etc/nginx/conf.d/default.conf - ./license.jwt:/etc/nginx/license.jwt # Only necessary when using NGINX Plus networks: - waf_network ports: - "80:80" waf-enforcer: container_name: waf-enforcer image: waf-enforcer: environment: - ENFORCER_PORT=50000 ports: - "50000:50000" volumes: - /opt/app_protect/bd_config:/opt/app_protect/bd_config networks: - waf_network restart: always waf-config-mgr: container_name: waf-config-mgr image: waf-config-mgr: volumes: - /opt/app_protect/bd_config:/opt/app_protect/bd_config - /opt/app_protect/config:/opt/app_protect/config - /etc/app_protect/conf:/etc/app_protect/conf restart: always network_mode: none depends_on: waf-enforcer: condition: service_started networks: waf_network: driver: bridge ``` To start the F5 WAF for NGINX services, use `docker compose up` in the same folder as the _docker-compose.yml_ file: ```shell sudo docker compose up -d ``` You can now review the operational status of F5 WAF for NGINX using the [Post-installation checks](/waf/install/docker.md#post-installation-checks). ## Hybrid configuration ### Additional requirements Besides the prerequisites outlined in the [Before you begin](#before-you-begin) section, you will require: - A working [NGINX Open Source](/nginx/admin-guide/installing-nginx/installing-nginx-open-source.md) or [NGINX Plus](/nginx/admin-guide/installing-nginx/installing-nginx-plus.md) instance. ### Install F5 WAF for NGINX packages Navigate to your chosen operating system, which are alphabetically ordered. #### Alpine Linux #### NGINX Open Source Add the F5 WAF for NGINX repository: ```shell printf "https://pkgs.nginx.com/app-protect-x-oss/alpine/v`egrep -o '^[0-9]+\.[0-9]+' /etc/alpine-release`/main\n" | sudo tee -a /etc/apk/repositories ``` Update the repositories, then install the F5 WAF for NGINX package and its dependencies: ```shell sudo apk update sudo apk add app-protect-module-oss ``` #### NGINX Plus Add the F5 WAF for NGINX repository: ```shell printf "https://pkgs.nginx.com/app-protect-x-plus/alpine/v`egrep -o '^[0-9]+\.[0-9]+' /etc/alpine-release`/main\n" | sudo tee -a /etc/apk/repositories ``` Update the repositories, then install the F5 WAF for NGINX package and its dependencies: ```shell sudo apk update sudo apk add openssl ca-certificates app-protect-module-plus ``` #### Amazon Linux #### NGINX Open Source Create a file for the F5 WAF for NGINX repository: `/etc/yum.repos.d/app-protect-x-oss.repo` ```shell [app-protect-x-oss] name=nginx-app-protect repo baseurl=https://pkgs.nginx.com/app-protect-x-oss/amzn/2023/$basearch/ sslclientcert=/etc/ssl/nginx/nginx-repo.crt sslclientkey=/etc/ssl/nginx/nginx-repo.key gpgcheck=0 enabled=1 ``` Install the F5 WAF for NGINX package and its dependencies: ```shell sudo dnf install app-protect-module-oss ``` #### NGINX Plus Create a file for the F5 WAF for NGINX repository: `/etc/yum.repos.d/app-protect-x-plus.repo` ```shell [app-protect-x-plus] name=nginx-app-protect repo baseurl=https://pkgs.nginx.com/app-protect-x-plus/amzn/2023/$basearch/ sslclientcert=/etc/ssl/nginx/nginx-repo.crt sslclientkey=/etc/ssl/nginx/nginx-repo.key gpgcheck=0 enabled=1 ``` Install the F5 WAF for NGINX package and its dependencies: ```shell sudo dnf install app-protect-module-plus ``` #### Debian #### NGINX Open Source Add the F5 WAF for NGINX repository: ```shell printf "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \ https://pkgs.nginx.com/app-protect-x-oss/debian `lsb_release -cs` nginx-plus\n" | \ sudo tee /etc/apt/sources.list.d/nginx-app-protect.list ``` Update the repositories, then install the F5 WAF for NGINX package and its dependencies: ```shell sudo apt-get update sudo apt-get install app-protect-module-oss ``` #### NGINX Plus Add the F5 WAF for NGINX repository: ```shell printf "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \ https://pkgs.nginx.com/app-protect-x-plus/debian `lsb_release -cs` nginx-plus\n" | \ sudo tee /etc/apt/sources.list.d/nginx-app-protect.list ``` Update the repositories, then install the F5 WAF for NGINX package and its dependencies: ```shell sudo apt-get update sudo apt-get install app-protect-module-plus ``` #### Oracle Linux / RHEL / Rocky Linux 8 **Note:** The steps are identical for these platforms due to their similar architecture. #### NGINX Open Source Create a file for the F5 WAF for NGINX repository: `/etc/yum.repos.d/app-protect-x-oss.repo` ```shell [app-protect-x-oss] name=nginx-app-protect repo baseurl=https://pkgs.nginx.com/app-protect-x-oss/centos/7/$basearch/ sslclientcert=/etc/ssl/nginx/nginx-repo.crt sslclientkey=/etc/ssl/nginx/nginx-repo.key gpgcheck=0 enabled=1 ``` Install the F5 WAF for NGINX package and its dependencies: ```shell sudo yum install app-protect-module-oss ``` #### NGINX Plus Create a file for the F5 WAF for NGINX repository: `/etc/yum.repos.d/app-protect-x-plus.repo` ```shell [app-protect-x-plus] name=nginx-app-protect repo baseurl=https://pkgs.nginx.com/app-protect-x-plus/centos/8/$basearch/ sslclientcert=/etc/ssl/nginx/nginx-repo.crt sslclientkey=/etc/ssl/nginx/nginx-repo.key gpgcheck=0 enabled=1 ``` Install the F5 WAF for NGINX package and its dependencies: ```shell sudo dnf install app-protect-module-plus ``` #### Ubuntu #### NGINX Open Source Add the F5 WAF for NGINX repositories: ```shell printf "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \ https://pkgs.nginx.com/app-protect-x-oss/ubuntu `lsb_release -cs` nginx-plus\n" | \ sudo tee /etc/apt/sources.list.d/nginx-app-protect.list ``` Update the repositories, then install the F5 WAF for NGINX package and its dependencies: ```shell sudo apt-get update sudo apt-get install app-protect-module-oss ``` #### NGINX Plus Add the F5 WAF for NGINX repositories: ```shell printf "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \ https://pkgs.nginx.com/app-protect-x-plus/ubuntu `lsb_release -cs` nginx-plus\n" | \ sudo tee /etc/apt/sources.list.d/nginx-app-protect.list ``` Update the repository, then install the F5 WAF for NGINX package and its dependencies: ```shell sudo apt-get update sudo apt-get install app-protect-module-plus ``` #### RHEL / Rocky Linux 9 #### NGINX Open Source Create a file for the F5 WAF for NGINX repository: `/etc/yum.repos.d/app-protect-x-oss.repo` ```shell [app-protect-x-oss] name=nginx-app-protect repo baseurl=https://pkgs.nginx.com/app-protect-x-oss/centos/9/$basearch/ sslclientcert=/etc/ssl/nginx/nginx-repo.crt sslclientkey=/etc/ssl/nginx/nginx-repo.key gpgcheck=0 enabled=1 ``` Install the F5 WAF for NGINX package and its dependencies: ```shell sudo dnf install app-protect-module-oss ``` #### NGINX Plus Create a file for the F5 WAF for NGINX repository: `/etc/yum.repos.d/app-protect-x-plus.repo` ```shell [app-protect-x-plus] name=nginx-app-protect repo baseurl=https://pkgs.nginx.com/app-protect-x-plus/centos/9/$basearch/ sslclientcert=/etc/ssl/nginx/nginx-repo.crt sslclientkey=/etc/ssl/nginx/nginx-repo.key gpgcheck=0 enabled=1 ``` Install the F5 WAF for NGINX package and its dependencies: ```shell sudo dnf install app-protect-module-plus ``` #### RHEL 10 #### NGINX Open Source Create a file for the F5 WAF for NGINX repository: `/etc/yum.repos.d/app-protect-x-oss.repo` ```shell [app-protect-x-oss] name=nginx-app-protect repo baseurl=https://pkgs.nginx.com/app-protect-x-oss/centos/10/$basearch/ sslclientcert=/etc/ssl/nginx/nginx-repo.crt sslclientkey=/etc/ssl/nginx/nginx-repo.key gpgcheck=0 enabled=1 ``` Install the F5 WAF for NGINX package and its dependencies: ```shell sudo dnf install app-protect-module-oss ``` #### NGINX Plus Create a file for the F5 WAF for NGINX repository: `/etc/yum.repos.d/app-protect-x-plus.repo` ```shell [app-protect-x-plus] name=nginx-app-protect repo baseurl=https://pkgs.nginx.com/app-protect-x-plus/centos/10/$basearch/ sslclientcert=/etc/ssl/nginx/nginx-repo.crt sslclientkey=/etc/ssl/nginx/nginx-repo.key gpgcheck=0 enabled=1 ``` Install the F5 WAF for NGINX package and its dependencies: ```shell sudo dnf install app-protect-module-plus ``` ### Configure Docker First, create new directories for the services: ```shell sudo mkdir -p /opt/app_protect/config /opt/app_protect/bd_config ``` Then assign new owners, with `101:101` as the default UID/GID ```shell sudo chown -R 101:101 /opt/app_protect/ ``` #### Download Docker images [Access to NGINX repo private-registry.nginx.com](/waf/install/docker.md#configure-docker-for-the-f5-container-registry) is needed to pull the following container images Download the `waf-enforcer` and `waf-config-mgr` images. Replace `5.2.0` with the release version you are deploying. ```shell docker pull private-registry.nginx.com/nap/waf-enforcer:5.2.0 docker pull private-registry.nginx.com/nap/waf-config-mgr:5.2.0 ``` #### Create and run a Docker Compose file Create a _docker-compose.yml_ file with the following contents in your host environment, replacing image tags as appropriate: ```yaml services: waf-enforcer: container_name: waf-enforcer image: waf-enforcer:5.2.0 environment: - ENFORCER_PORT=50000 ports: - "50000:50000" volumes: - /opt/app_protect/bd_config:/opt/app_protect/bd_config networks: - waf_network restart: always waf-config-mgr: container_name: waf-config-mgr image: waf-config-mgr:5.2.0 volumes: - /opt/app_protect/bd_config:/opt/app_protect/bd_config - /opt/app_protect/config:/opt/app_protect/config - /etc/app_protect/conf:/etc/app_protect/conf restart: always network_mode: none depends_on: waf-enforcer: condition: service_started networks: waf_network: driver: bridge ``` To start the F5 WAF for NGINX services, use `docker compose up` in the same folder as the _docker-compose.yml_ file: ```shell sudo docker compose up -d ``` F5 WAF for NGINX should now be operational, and you can move onto [Post-installation checks](#post-installation-checks). ## Single container configuration ### Create configuration files Copy or move your subscription files into a new folder. In the same folder, create three files: - _nginx.conf_ - An NGINX configuration file with F5 WAF for NGINX enabled - _entrypoint.sh_ - A Docker startup script which spins up all F5 WAF for NGINX processes, requiring executable permissions - _custom_log_format.json_ - An optional user-defined security log format file **Note:** If you are not using `custom_log_format.json`, you should remove any references to it from your nginx.conf and entrypoint.sh files. Here are examples of the file contents: #### nginx.conf ```nginx {hl_lines=[4, 26, 27, 28]} user nginx; worker_processes auto; load_module modules/ngx_http_app_protect_module.so; error_log /var/log/nginx/error.log warn; events { worker_connections 10240; } http { include /etc/nginx/mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; upstream app_backend_com { server 192.168.0.1:8000; server 192.168.0.1:8001; } server { listen 80; server_name app.example.com; app_protect_enable on; app_protect_security_log_enable on; app_protect_security_log "/etc/nginx/custom_log_format.json" syslog:server=127.0.0.1:514; location / { client_max_body_size 0; default_type text/html; # set your backend here proxy_pass http://app_backend_com; proxy_set_header Host $host; } } } ``` #### entrypoint.sh ```shell #!/bin/sh /bin/su -s /bin/sh -c "/usr/share/ts/bin/bd-socket-plugin tmm_count 4 proc_cpuinfo_cpu_mhz 2000000 total_xml_memory 307200000 total_umu_max_size 3129344 sys_max_account_id 1024 no_static_config 2>&1 >> /var/log/app_protect/bd-socket-plugin.log &" nginx /usr/sbin/nginx -g 'daemon off;' # Optional line for the IP intelligence feature /opt/app_protect/bin/iprepd /etc/app_protect/tools/iprepd.cfg > ipi.log 2>&1 & ``` #### custom_log_format.json ```json { "filter": { "request_type": "all" }, "content": { "format": "splunk", "max_request_size": "any", "max_message_size": "10k" } } ``` ### Create a Dockerfile Copy or move your subscription files into a new folder. In the same folder as the subscription files, create a _Dockerfile_ based on your [desired operating system](/waf/fundamentals/technical-specifications.md#supported-operating-systems) image using an example from the following sections. **Note:** If you are not using using `custom_log_format.json` or the IP intelligence feature, you should remove any references to them from your Dockerfile. #### Alpine Linux ```dockerfile # syntax=docker/dockerfile:1 # For Alpine 3.22: FROM alpine:3.22 # Download and add the NGINX signing keys: RUN wget -O /etc/apk/keys/nginx_signing.rsa.pub https://cs.nginx.com/static/keys/nginx_signing.rsa.pub \ && wget -O /etc/apk/keys/app-protect-security-updates.rsa.pub https://cs.nginx.com/static/keys/app-protect-security-updates.rsa.pub # Add NGINX Plus repository: RUN printf "https://pkgs.nginx.com/plus/alpine/v`egrep -o '^[0-9]+\.[0-9]+' /etc/alpine-release`/main\n" | tee -a /etc/apk/repositories # Add F5 WAF for NGINX repository: RUN printf "https://pkgs.nginx.com/app-protect/alpine/v`egrep -o '^[0-9]+\.[0-9]+' /etc/alpine-release`/main\n" | tee -a /etc/apk/repositories \ && printf "https://pkgs.nginx.com/app-protect-security-updates/alpine/v`egrep -o '^[0-9]+\.[0-9]+' /etc/alpine-release`/main\n" | tee -a /etc/apk/repositories # Update the repository and install the most recent version of the F5 WAF for NGINX package (which includes NGINX Plus): RUN --mount=type=secret,id=nginx-crt,dst=/etc/apk/cert.pem,mode=0644 \ --mount=type=secret,id=nginx-key,dst=/etc/apk/cert.key,mode=0644 \ apk update && apk add app-protect # Only use if you want to install and use the IP intelligence feature: RUN --mount=type=secret,id=nginx-crt,dst=/etc/apk/cert.pem,mode=0644 \ --mount=type=secret,id=nginx-key,dst=/etc/apk/cert.key,mode=0644 \ apk update && apk add app-protect-ip-intelligence # Securely copy the JWT license: RUN --mount=type=secret,id=license-jwt,dst=license.jwt \ cp license.jwt /etc/nginx/license.jwt # Forward request logs to Docker log collector: RUN ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log # Copy configuration files: COPY nginx.conf custom_log_format.json /etc/nginx/ COPY entrypoint.sh /root/ CMD ["sh", "/root/entrypoint.sh"] ``` #### Amazon Linux ```dockerfile # syntax=docker/dockerfile:1 # For Amazon Linux 2023: FROM amazonlinux:2023 # Install prerequisite packages: RUN dnf -y install wget ca-certificates # Add NGINX Plus repo: RUN wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/plus-amazonlinux2023.repo # Add NAP dependencies repo: RUN wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/dependencies.amazonlinux2023.repo # Add NGINX App-protect repo: RUN wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/app-protect-amazonlinux2023.repo # Install F5 WAF for NGINX: RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ --mount=type=secret,id=nginx-key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ dnf -y install app-protect \ && dnf clean all \ && rm -rf /var/cache/yum # Only use if you want to install and use the IP intelligence feature: RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ --mount=type=secret,id=nginx-key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ dnf -y install app-protect-ip-intelligence # Securely copy the JWT license: RUN --mount=type=secret,id=license-jwt,dst=license.jwt \ cp license.jwt /etc/nginx/license.jwt # Forward request logs to Docker log collector: RUN ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log # Copy configuration files: COPY nginx.conf custom_log_format.json /etc/nginx/ COPY entrypoint.sh /root/ CMD ["sh", "/root/entrypoint.sh"] ``` #### Debian ```dockerfile ARG OS_CODENAME # Where OS_CODENAME can be: buster/bullseye/bookworm # syntax=docker/dockerfile:1 # For Debian 11 / 12: FROM debian:${OS_CODENAME} # Install prerequisite packages: RUN apt-get update && apt-get install -y apt-transport-https lsb-release ca-certificates wget gnupg2 # Download and add the NGINX signing keys: RUN wget -qO - https://cs.nginx.com/static/keys/nginx_signing.key | \ gpg --dearmor | tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null RUN wget -qO - https://cs.nginx.com/static/keys/app-protect-security-updates.key | \ gpg --dearmor | tee /usr/share/keyrings/app-protect-security-updates.gpg >/dev/null # Add NGINX Plus repository: RUN printf "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \ https://pkgs.nginx.com/plus/debian `lsb_release -cs` nginx-plus\n" | \ tee /etc/apt/sources.list.d/nginx-plus.list # Add F5 WAF for NGINX repositories: RUN printf "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \ https://pkgs.nginx.com/app-protect/debian `lsb_release -cs` nginx-plus\n" | \ tee /etc/apt/sources.list.d/nginx-app-protect.list RUN printf "deb [signed-by=/usr/share/keyrings/app-protect-security-updates.gpg] \ https://pkgs.nginx.com/app-protect-security-updates/debian `lsb_release -cs` nginx-plus\n" | \ tee /etc/apt/sources.list.d/app-protect-security-updates.list # Download the apt configuration to `/etc/apt/apt.conf.d`: RUN wget -P /etc/apt/apt.conf.d https://cs.nginx.com/static/files/90pkgs-nginx # Update the repository and install the most recent version of the F5 WAF for NGINX package (which includes NGINX Plus): RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ --mount=type=secret,id=nginx-key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ apt-get update && apt-get install -y app-protect # Only use if you want to install and use the IP intelligence feature: RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ --mount=type=secret,id=nginx-key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ apt-get install -y app-protect-ip-intelligence # Securely copy the JWT license: RUN --mount=type=secret,id=license-jwt,dst=license.jwt \ cp license.jwt /etc/nginx/license.jwt # Forward request logs to Docker log collector: RUN ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log # Copy configuration files: COPY nginx.conf custom_log_format.json /etc/nginx/ COPY entrypoint.sh /root/ CMD ["sh", "/root/entrypoint.sh"] ``` #### Oracle Linux ```dockerfile # syntax=docker/dockerfile:1 # For Oracle Linux 8: FROM oraclelinux:8 # Install prerequisite packages: RUN dnf -y install wget ca-certificates yum-utils # Add NGINX Plus repo to Yum: RUN wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/nginx-plus-8.repo # Add NGINX App-protect repo to Yum: RUN wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/app-protect-8.repo # Enable Yum repositories to pull F5 WAF for NGINX dependencies: RUN dnf config-manager --set-enabled ol8_codeready_builder \ && wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/dependencies.repo \ # You can use either of the dependencies or epel repo # && rpm -ivh https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm \ && dnf clean all # Install F5 WAF for NGINX: RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ --mount=type=secret,id=nginx-key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ dnf -y install app-protect \ && dnf clean all \ && rm -rf /var/cache/dnf # Only use if you want to install and use the IP intelligence feature: RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ --mount=type=secret,id=nginx-key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ dnf install -y app-protect-ip-intelligence # Securely copy the JWT license: RUN --mount=type=secret,id=license-jwt,dst=license.jwt \ cp license.jwt /etc/nginx/license.jwt # Forward request logs to Docker log collector: RUN ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log # Copy configuration files: COPY nginx.conf custom_log_format.json /etc/nginx/ COPY entrypoint.sh /root/ CMD ["sh", "/root/entrypoint.sh"] ``` #### RHEL 8 ```dockerfile # syntax=docker/dockerfile:1 # For RHEL ubi8: FROM registry.access.redhat.com/ubi8/ubi # Install prerequisite packages: RUN dnf -y install wget ca-certificates # Add NGINX Plus repo to Yum: RUN wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/nginx-plus-8.repo # Add NGINX App-protect & dependencies repo to Yum: RUN wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/app-protect-8.repo RUN wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/dependencies.repo \ # You can use either of the dependencies or epel repo # && rpm -ivh https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm \ && dnf clean all # Install F5 WAF for NGINX: RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ --mount=type=secret,id=nginx-key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ dnf install --enablerepo=codeready-builder-for-rhel-8-x86_64-rpms -y app-protect \ && dnf clean all \ && rm -rf /var/cache/dnf # Only use if you want to install and use the IP intelligence feature: RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ --mount=type=secret,id=nginx-key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ dnf install -y app-protect-ip-intelligence # Securely copy the JWT license: RUN --mount=type=secret,id=license-jwt,dst=license.jwt \ cp license.jwt /etc/nginx/license.jwt # Forward request logs to Docker log collector: RUN ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log # Copy configuration files: COPY nginx.conf custom_log_format.json /etc/nginx/ COPY entrypoint.sh /root/ CMD ["sh", "/root/entrypoint.sh"] ``` #### RHEL 9 ```dockerfile # syntax=docker/dockerfile:1 # For Rocky Linux 9: FROM rockylinux:9 # Install prerequisite packages: RUN dnf -y install wget ca-certificates 'dnf-command(config-manager)' # Add NGINX Plus repo to Yum: RUN wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/plus-9.repo # Add NGINX App-protect & dependencies repo to Yum: RUN wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/app-protect-9.repo RUN dnf config-manager --set-enabled crb \ && wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/dependencies.repo \ && dnf clean all # Install F5 WAF for NGINX: RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ --mount=type=secret,id=nginx-key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ dnf install -y app-protect \ && dnf clean all \ && rm -rf /var/cache/dnf # Only use if you want to install and use the IP intelligence feature: RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ --mount=type=secret,id=nginx-key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ dnf install -y app-protect-ip-intelligence # Forward request logs to Docker log collector: RUN ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log # Securely copy the JWT license: RUN --mount=type=secret,id=license-jwt,dst=license.jwt \ cp license.jwt /etc/nginx/license.jwt # Copy configuration files: COPY nginx.conf custom_log_format.json /etc/nginx/ COPY entrypoint.sh /root/ CMD ["sh", "/root/entrypoint.sh"] ``` #### Rocky Linux 9 ```dockerfile # syntax=docker/dockerfile:1 # For Rocky Linux 9: FROM rockylinux:9 # Install prerequisite packages: RUN dnf -y install wget ca-certificates 'dnf-command(config-manager)' # Add NGINX Plus repo to Yum: RUN wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/plus-9.repo # Add NGINX App-protect & dependencies repo to Yum: RUN wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/app-protect-9.repo RUN dnf config-manager --set-enabled crb \ && wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/dependencies.repo \ && dnf clean all # Install F5 WAF for NGINX: RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ --mount=type=secret,id=nginx-key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ dnf install -y app-protect \ && dnf clean all \ && rm -rf /var/cache/dnf # Only use if you want to install and use the IP intelligence feature: RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ --mount=type=secret,id=nginx-key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ dnf install -y app-protect-ip-intelligence # Securely copy the JWT license: RUN --mount=type=secret,id=license-jwt,dst=license.jwt \ cp license.jwt /etc/nginx/license.jwt # Forward request logs to Docker log collector: RUN ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log # Copy configuration files: COPY nginx.conf custom_log_format.json /etc/nginx/ COPY entrypoint.sh /root/ CMD ["sh", "/root/entrypoint.sh"] ``` #### Ubuntu ```dockerfile ARG OS_CODENAME # Where OS_CODENAME can be: focal/jammy/noble # syntax=docker/dockerfile:1 # For Ubuntu 20.04 / 22.04 / 24.04: FROM ubuntu:${OS_CODENAME} # Install prerequisite packages: RUN apt-get update && apt-get install -y apt-transport-https lsb-release ca-certificates wget gnupg2 # Download and add the NGINX signing keys: RUN wget -qO - https://cs.nginx.com/static/keys/nginx_signing.key | \ gpg --dearmor | tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null RUN wget -qO - https://cs.nginx.com/static/keys/app-protect-security-updates.key | \ gpg --dearmor | tee /usr/share/keyrings/app-protect-security-updates.gpg >/dev/null # Add NGINX Plus repository: RUN printf "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \ https://pkgs.nginx.com/plus/ubuntu `lsb_release -cs` nginx-plus\n" | \ tee /etc/apt/sources.list.d/nginx-plus.list # Add F5 WAF for NGINX repositories: RUN printf "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \ https://pkgs.nginx.com/app-protect/ubuntu `lsb_release -cs` nginx-plus\n" | \ tee /etc/apt/sources.list.d/nginx-app-protect.list RUN printf "deb [signed-by=/usr/share/keyrings/app-protect-security-updates.gpg] \ https://pkgs.nginx.com/app-protect-security-updates/ubuntu `lsb_release -cs` nginx-plus\n" | \ tee /etc/apt/sources.list.d/app-protect-security-updates.list # Download the apt configuration to `/etc/apt/apt.conf.d`: RUN wget -P /etc/apt/apt.conf.d https://cs.nginx.com/static/files/90pkgs-nginx # Update the repository and install the most recent version of the F5 WAF for NGINX package (which includes NGINX Plus): RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ --mount=type=secret,id=nginx-key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ apt-get update && DEBIAN_FRONTEND="noninteractive" apt-get install -y app-protect # Only use if you want to install and use the IP intelligence feature: RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ --mount=type=secret,id=nginx-key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ apt-get install -y app-protect-ip-intelligence # Securely copy the JWT license: RUN --mount=type=secret,id=license-jwt,dst=license.jwt \ cp license.jwt /etc/nginx/license.jwt # Forward request logs to Docker log collector: RUN ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log # Copy configuration files: COPY nginx.conf custom_log_format.json /etc/nginx/ COPY entrypoint.sh /root/ CMD ["sh", "/root/entrypoint.sh"] ``` ### Build the Docker image Your folder should contain the following files: - _nginx-repo.crt_ - _nginx-repo.key_ - _license.jwt_ (Only necessary when using NGINX Plus) - _nginx.conf_ - _entrypoint.sh_ - _Dockerfile_ - _custom_log_format.json_ #### Building an image with NGINX Plus To build an image for NGINX Plus, use the following command that is not RHEL-based, replacing `` as appropriate: ```shell sudo docker build --no-cache --platform linux/amd64 --secret id=nginx-crt,src=nginx-repo.crt --secret id=nginx-key,src=nginx-repo.key --secret id=license-jwt,src=license.jwt -t . ``` A RHEL-based system would use the following command instead: ```shell podman build --no-cache --secret id=nginx-crt,src=nginx-repo.crt --secret id=nginx-key,src=nginx-repo.key --secret id=license-jwt,src=license.jwt -t . ``` #### Building an image with NGINX Open Source To build an image for NGINX Open Source, use the following command that is not RHEL-based, replacing `` as appropriate: ```shell sudo docker build --no-cache --platform linux/amd64 --secret id=nginx-crt,src=nginx-repo.crt --secret id=nginx-key,src=nginx-repo.key -t . ``` A RHEL-based system would use the following command instead: ```shell podman build --no-cache --secret id=nginx-crt,src=nginx-repo.crt --secret id=nginx-key,src=nginx-repo.key -t . ``` **Note:** The `--no-cache` option is used to ensure the image is built from scratch, installing the latest versions of NGINX Plus and F5 WAF for NGINX. Verify that your image has been created using the `docker images` command: ```shell docker images ``` Create a container based on this image, replacing as appropriate: ```shell docker run --name -p 80:80 -d ``` Verify the new container is running using the `docker ps` command: ```shell docker ps ``` ### Update configuration files Once you have installed F5 WAF for NGINX, you must load it as a module in the main context of your NGINX configuration. ```nginx load_module modules/ngx_http_app_protect_module.so; ``` The Enforcer address must be added at the _http_ context: ```nginx app_protect_enforcer_address 127.0.0.1:50000; ``` And finally, F5 WAF for NGINX can enabled on a _http_, _server_ or _location_ context: ```nginx app_protect_enable on; ``` **Note:** You should only enable F5 WAF for NGINX on _proxy_pass_ and _grpc_pass_ locations. Here are two examples of how these additions could look in configuration files: #### nginx.conf The default path for this file is `/etc/nginx/nginx.conf`. ```nginx {hl_lines=[5, 33]} user nginx; worker_processes auto; # F5 WAF for NGINX load_module modules/ngx_http_app_protect_module.so; error_log /var/log/nginx/error.log notice; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; keepalive_timeout 65; #gzip on; # F5 WAF for NGINX app_protect_enforcer_address 127.0.0.1:50000; include /etc/nginx/conf.d/*.conf; } ``` #### default.conf The default path for this file is `/etc/nginx/conf.d/default.conf`. ```nginx {hl_lines=[10]} server { listen 80; server_name domain.com; location / { # F5 WAF for NGINX app_protect_enable on; client_max_body_size 0; default_type text/html; proxy_pass http://127.0.0.1:8080/; } } server { listen 8080; server_name localhost; location / { root /usr/share/nginx/html; index index.html index.htm; } # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } } ``` Once you have updated your configuration files, you can reload NGINX to apply the changes. You have two options depending on your environment: - `nginx -s reload` - `sudo systemctl reload nginx` F5 WAF for NGINX should now be operational, and you can move onto [Post-installation checks](#post-installation-checks). ## Post-installation checks The following steps check that F5 WAF for NGINX enforcement is operational. They should be ran in the environment with the WAF components. Check that the three processes for F5 WAF for NGINX are running using `ps aux`: - _bd-socket-plugin_ - _nginx: master process_ - _nginx: worker process_ ```shell USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 8 1.3 2.4 3486948 399092 ? Sl 09:11 0:02 /usr/share/ts/bin/bd-socket-plugin tmm_count 4 proc_cpuinfo_cpu_mhz 2000000 total_xml_memory 307200000 total_umu_max_size 3129344 sys_max_account_id 1024 no_static_config root 14 0.0 0.1 71060 26680 ? S 09:11 0:00 nginx: master process /usr/sbin/nginx -c /tmp/policy/test_nginx.conf -g daemon off; root 26 0.0 0.3 99236 52092 ? S 09:12 0:00 nginx: worker process root 28 0.0 0.0 11788 2920 pts/0 Ss 09:12 0:00 bash root 43 0.0 0.0 47460 3412 pts/0 R+ 09:14 0:00 ps aux ``` Verify there are no errors in the file `/var/log/nginx/error.log` and that the policy compiled successfully: ```none 2020/05/10 13:21:04 [notice] 402#402: APP_PROTECT { "event": "configuration_load_start", "configSetFile": "/opt/f5waf/config/config_set.json" } 2020/05/10 13:21:04 [notice] 402#402: APP_PROTECT policy 'app_protect_default_policy' from: /etc/app_protect/conf/NginxDefaultPolicy.json compiled successfully 2020/05/10 13:21:04 [notice] 402#402: APP_PROTECT { "event": "configuration_load_success", "software_version": "1.1.1", "attack_signatures_package":{"revision_datetime":"2019-07-16T12:21:31Z"},"completed_successfully":true} 2020/05/10 13:21:04 [notice] 402#402: using the "epoll" event method 2020/05/10 13:21:04 [notice] 402#402: nginx/1.17.6 (nginx-plus-r20) 2020/05/10 13:21:04 [notice] 402#402: built by gcc 4.8.5 20150623 (Red Hat 4.8.5-36) (GCC) 2020/05/10 13:21:04 [notice] 402#402: OS: Linux 3.10.0-957.27.2.el7.x86_64 2020/05/10 13:21:04 [notice] 402#402: getrlimit(RLIMIT_NOFILE): 1048576:1048576 2020/05/10 13:21:04 [notice] 406#406: start worker processes 2020/05/10 13:21:04 [notice] 406#406: start worker process 407 ``` Check that sending an attack signature in a request returns a response block page containing a support ID: ```shell Request: http://10.240.185.211/?a=