{"id":22096024,"url":"https://github.com/perimeterx/perimeterx-nginx-plugin","last_synced_at":"2025-05-09T02:45:14.828Z","repository":{"id":37734767,"uuid":"47504823","full_name":"PerimeterX/perimeterx-nginx-plugin","owner":"PerimeterX","description":"PerimeterX NGINX Lua Middleware","archived":false,"fork":false,"pushed_at":"2024-12-26T15:53:53.000Z","size":4457,"stargazers_count":43,"open_issues_count":0,"forks_count":21,"subscribers_count":25,"default_branch":"master","last_synced_at":"2025-03-31T21:33:31.796Z","etag":null,"topics":["enforcer","lua-nginx","perimeterx"],"latest_commit_sha":null,"homepage":"","language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/PerimeterX.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-12-06T16:41:36.000Z","updated_at":"2024-12-26T15:30:39.000Z","dependencies_parsed_at":"2025-01-03T12:11:47.252Z","dependency_job_id":"081df059-46b4-4b9a-8e47-94fa9ab49db3","html_url":"https://github.com/PerimeterX/perimeterx-nginx-plugin","commit_stats":null,"previous_names":[],"tags_count":91,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PerimeterX%2Fperimeterx-nginx-plugin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PerimeterX%2Fperimeterx-nginx-plugin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PerimeterX%2Fperimeterx-nginx-plugin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PerimeterX%2Fperimeterx-nginx-plugin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PerimeterX","download_url":"https://codeload.github.com/PerimeterX/perimeterx-nginx-plugin/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253181025,"owners_count":21866988,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["enforcer","lua-nginx","perimeterx"],"created_at":"2024-12-01T04:09:23.447Z","updated_at":"2025-05-09T02:45:14.807Z","avatar_url":"https://github.com/PerimeterX.png","language":"Lua","funding_links":[],"categories":[],"sub_categories":[],"readme":"![image](https://storage.googleapis.com/perimeterx-logos/primary_logo_red_cropped.png)\n\n# [PerimeterX](http://www.perimeterx.com) NGINX Lua Plugin\n\n\u003e Latest stable version: [v7.3.4](https://luarocks.org/modules/bendpx/perimeterx-nginx-plugin/7.3.4-1)\n\n## [Introduction](#introduction)\n\n## [Upgrading](#upgradingVersions)\n\n- [From any Version Lower than 4.x](#3x4x)\n- [From any Version Above 4.x](#4x)\n\n## [Installation](#installation)\n\n- [Supported Operating Systems](#supported_os)\n- [Supported NGINX Versions](#supported_versions)\n- [Installing with Ubuntu](#ubuntu)\n- [Installing with CentOS7](#centos7)\n- [Installing the PerimeterX NGINX Plugin for NGINX+](#installation_nginxplus_px)\n- [Required NGINX Configuration](#nginx_configuration)\n  - [Resolver](#nginx_resolver)\n  - [Lua Package Path](#nginx_lua_package_path)\n  - [Lua CA Certificates](#nginx_lua_ca_certificates)\n  - [Lua Timer Initialization](#nginx_lua_timer_initialization)\n  - [PerimeterX enforcement](#nginx_perimeterx_enforcement)\n  - [NGINX.conf Example](#nginx_config_example)\n\n## [Configuration](#configuration)\n\n- [Required Configuration](#perimterx_required_parameters)\n- [First-Party Configuration](#first_party_config)\n  - [First-Party Mode](#first-party)\n  - [PerimeterX First-Party JS Snippet](#perimterx_first_party_js_snippet)\n- [Optional Configuration](#advanced_configuration)\n  - [Monitor / Block Mode](#monitoring_mode)\n  - [Debug Mode](#debug-mode)\n  - [Whitelisting](#whitelisting)\n  - [Filter Sensitive Headers](#sensitive-headers)\n  - [Enabled Routes](#enabled-routes)\n  - [Custom Enabled Routes](#custom-enabled-routes)\n  - [Monitored Routes](#monitored-routes)\n  - [Sensitive Routes](#sensitive-routes)\n  - [Sensitive Routes Regex List](#sensitive-routes-regex)\n  - [Custom Sensitive Routes](#custom-sensitive-routes)\n  - [API Timeout](#api-timeout)\n  - [Customize Default Block Page](#customblockpage)\n  - [Redirect to a Custom Block Page URL](#redirect_to_custom_blockpage)\n  - [Redirect on Custom URL](#redirect_on_custom_url)\n  - [Redirect to Subdomain](#redirect_to_subdomain)\n  - [Additional Activity Handler](#add-activity-handler)\n  - [Enrich Custom Parameters](#custom-parameters)\n  - [Blocking Score](#blocking-score)\n  - [First-Party Prefix](#first-party-prefix)\n  - [Advanced Blocking Response](#json-response-enabled)\n  - [Proxy Support](#proxy-url)\n  - [Proxy Authorization Header](#proxy-authorization)\n  - [Custom Cookie Header](#custom-cookie-header)\n  - [Bypass Monitor Mode Header](#bypass-monitor-header)\n  - [Secured PXHD Cookie](#pxhd-cookie)\n\n## [Enrichment](#enrichment)\n\n - [Data Enrichment](#data-enrichment)\n - [Log Enrichment](#log-enrichment)\n\n## [Advanced Blocking Response](#advancedBlockingResponse)\n\n## [Login Credentials Extraction](#loginCredentialsExtraction)\n\n- [Login Credentials Extraction Configuration](#loginCredentialsExtractionConfiguration)\n - [Enable Login Credentials Extraction](#px_enable_login_creds_extraction)\n - [Credentials JSON file](#px_login_creds_settings_filename)\n - [Credentials Intelligence Version](#px_credentials_intelligence_version)\n - [Additional s2s Activity Header](#px_additional_s2s_activity_header_enabled)\n - [Send Raw Username On Additional s2s Activity](#px_send_raw_username_on_additional_s2s_activity)\n - [Compromised Credentials Header Name](#px_compromised_credentials_header_name)\n - [Login Successful Reporting Method](#px_login_successful_reporting_method)\n - [Login Successful Header Name](#px_login_successful_header_name)\n - [Login Successful Header Value](#px_login_successful_header_value)\n - [Login Successful Status](#px_login_successful_status)\n - [Login Successful Custom Function](#custom_login_successful)\n\n## [HypeSale](#hypesale)\n\n - [HypeSale host](#hypesale_host)\n\n## [Sensitive GraphQL Operations](#graphql)\n\n - [Sensitive GraphQL Operation Types](#px_sensitive_graphql_operation_types)\n - [Sensitive GraphQL Operation Names](#px_sensitive_graphql_operation_names)\n - [Sensitive GraphQL routes](#px_sensitive_graphql_routes)\n\n\n## [Appendix](#appendix)\n\n - [HTTP v2 Support](#http2)\n - [NGINX Plus](#nginxplus)\n - [NGINX Dynamic Modules](#dynamicmodules)\n - [Multiple App Support](#multipleapps)\n - [Setting Up A First Party Prefix](#setting_up_first_party_prefix)\n - [URI Delimiters](#uri_delimiters)\n\n## [Test Environment](#test_environment)\n\n## [Contributing](#contributing)\n\n## \u003ca name=\"introduction\"\u003e\u003c/a\u003e Introduction\n\nThe PerimeterX Nginx Lua Plugin is a Lua module that enforces whether or not\na request is allowed to continue being processed. When the PerimeterX Enforcer determines that a request is coming from a non-human source the request is blocked.\n\n## \u003ca name=\"upgradingVersions\"\u003e\u003c/a\u003e Upgrading\n\nSee the full [changelog](CHANGELOG.md) for all versions.\n\n#### \u003ca name=\"3x4x\"\u003e\u003c/a\u003e From any Version Lower than 4.x\n\nAs of version 4.x the config builder was added. The config builder adds default values to properties that are not implicitly specified. This change requires the user to import the configuration in the `init_worker_by_lua_block` and `access_by_lua_block` blocks inside `nginx.conf`:\n\n1. Modify `init_worker_by_lua_block`\n\n```lua\n    init_worker_by_lua_block {\n        local pxconfig = require(\"px.pxconfig\")\n        require (\"px.utils.pxtimer\").application(pxconfig)\n    }\n```\n\n2. Modify `access_by_lua_block`\n\n```lua\n    access_by_lua_block {\n        local config = require('px.pxconfig')\n        require(\"px.pxnginx\").application(config)\n    }\n```\n\n3. Modify `header_filter_by_lua_block`\n\n```lua\n    header_filter_by_lua_block {\n        require(\"px.pxnginx\").finalize()\n    }\n```\n\n#### \u003ca name=\"4x\"\u003e\u003c/a\u003e From any Version above 4.x\n\nTo upgrade to the latest Enforcer version, [re-install](#installation) the Enforcer according to your OS.\n\n## \u003ca name=\"installation\"\u003e\u003c/a\u003eInstallation\n\n#### \u003ca name=\"supported_os\"\u003e\u003c/a\u003e Supported Operating Systems\n\n- Debian\n- [Ubuntu 14.04](#ubuntu1404) or [Ubuntu 16.04+](#ubuntu1604)\n- RHEL\n- [CentOS 7](#centos7)\n- Amazon Linux (AMI)\n\n#### \u003ca name=\"supported_versions\"\u003e\u003c/a\u003eSupported NGINX Versions:\n\nRecommended that you use the newest version of NGINX from the [Official NGINX](http://nginx.org/en/linux_packages.html) repo.\n\n- [NGINX 1.7 or later](#installation_px)\n  - [Lua NGINX Module V0.9.11 or later](#installation_px)\n- [NGINX Plus](#installation_nginxplus_px)\n  - [Lua NGINX Plus Module](#installation_nginxplus_px)\n- [OpenResty](https://openresty.org/en/)\n\n\u003e NOTE: Using the default NGINX provide by default in various Operating Systems does not support the LUA NGINX Module.\n\n### \u003ca name=\"ubuntu\"\u003e\u003c/a\u003e Installing with Ubuntu\n\n#### \u003ca name=\"ubuntu1404\"\u003e\u003c/a\u003eUbuntu 14.04\n\n###### 1. Upgrade and update your existing dependencies for Ubuntu 16.04 or higher\n\n```sh\nsudo apt-get update\nsudo apt-get upgrade\n```\n\n###### 2. Add the official NGINX repository to get the latest version of NGINX\n\n```sh\nsudo add-apt-repository ppa:nginx/stable\n```\n\nIf an `add-apt-repository: command not found` error is returned, run:\n\n`sudo apt-get -y install software-properties-common`\n\n###### 3. Install the dependencies for Ubuntu 14.04:\n\n```sh\nsudo apt-get -y install build-essential\nsudo apt-get -y install ca-certificates\nsudo apt-get -y install make\nsudo apt-get -y install wget\nsudo apt-get -y install nginx\nsudo apt-get -y install m4\nsudo apt-get -y install libnginx-mod-http-lua\nsudo apt-get -y install lua-cjson\n```\n\n###### 4. Download and install LuaRocks from source\n\n```sh\nwget http://luarocks.github.io/luarocks/releases/luarocks-2.4.4.tar.gz\ntar -xzf luarocks-2.4.4.tar.gz\ncd luarocks-2.4.4\n./configure\nsudo make clean \u0026\u0026 sudo make build \u0026\u0026 sudo make install\ncd ~\n```\n\n###### 5. Download and install Nettle 3.3 from source\n\n```sh\nwget https://ftp.gnu.org/gnu/nettle/nettle-3.3.tar.gz\ntar -xzf nettle-3.3.tar.gz\ncd nettle-3.3\n./configure\nsudo make clean \u0026\u0026 sudo make install\ncd ~\n```\n\n###### 6. Install the remaining dependencies\n\n```sh\nsudo apt-get -y install lua-sec\nsudo luarocks install lua-resty-nettle\n\n```\n\n###### 7. Install the PerimeterX NGINX Plugin\n\n```sh\nsudo no_proxy=1 luarocks install perimeterx-nginx-plugin\n```\n\n##\n\n### \u003ca name=\"ubuntu1604\"\u003e\u003c/a\u003eUbuntu 16.04 and Higher\n\n###### 1. Update your existing dependencies for Ubuntu 16.04 or higher\n\n```sh\nsudo apt-get update\n```\n\n###### 2. Add the official NGINX repository to get the latest version of NGINX\n\n```sh\nsudo add-apt-repository ppa:nginx/stable\n```\n\nIf an `add-apt-repository: command not found` error is returned, run:\n\n`sudo apt-get -y install software-properties-common`\n\n###### 3. Update and upgrade your existing dependencies for Ubuntu 16.04 or higher\n\n```sh\nsudo apt-get update\nsudo apt-get upgrade\n```\n\n###### 4. Install the dependencies for Ubuntu 16.04 or higher\n\n```sh\nsudo apt-get -y install build-essential\nsudo apt-get -y install ca-certificates\nsudo apt-get -y install nginx\nsudo apt-get -y install libnginx-mod-http-lua\nsudo apt-get -y install lua-cjson\nsudo apt-get -y install libnettle6\nsudo apt-get -y install nettle-dev\nsudo apt-get -y install luarocks\nsudo apt-get -y install luajit\nsudo apt-get -y install libluajit-5.1-dev\n```\n\n###### 5. Install the PerimeterX NGINX Plugin\n\n```sh\nluarocks install perimeterx-nginx-plugin\n```\n\n##\n\n### \u003ca name=\"centos7\"\u003e\u003c/a\u003eInstalling with CentOS 7\n\nNGINX does not provide an NGINX http lua module for CentOS/RHEL via an RPM. This means that you need to compile the Module from source.\n\n###### 1. Update and Install dependencies\n\n```sh\nyum -y update\nyum install -y epel-release\nyum update -y\nyum groupinstall -y  \"Development Tools\"\nyum install -y wget rpmdevtools git luajit luajit-devel openssl-devel zlib-devel pcre-devel gcc gcc-c++ make perl-ExtUtils-Embed lua-json lua-devel  ca-certificates\nyum remove -y nettle luarocks\n```\n\n###### 2. Make a tmp directory to work in\n\n```sh\nsudo mkdir /tmp/nginx\ncd /tmp/nginx\n```\n\n###### 3. Download all required source files\n\n```sh\nwget http://luarocks.github.io/luarocks/releases/luarocks-3.5.0.tar.gz\nwget http://nginx.org/download/nginx-1.18.0.tar.gz\nwget -O luajit-2.0.tar.gz https://github.com/LuaJIT/LuaJIT/archive/refs/tags/v2.0.5.tar.gz\nwget -O nginx_devel_kit.tar.gz https://github.com/simpl/ngx_devel_kit/archive/v0.3.1.tar.gz\nwget -O nginx_lua_module.tar.gz https://github.com/openresty/lua-nginx-module/archive/v0.10.15.tar.gz\nwget https://ftp.gnu.org/gnu/nettle/nettle-3.6.tar.gz\n```\n\n###### 4. Unpackage all source files\n\n```sh\ntar -xzf luarocks-3.5.0.tar.gz\ntar -xzf nettle-3.6.tar.gz\ntar -xvf luajit-2.0.tar.gz\ntar -xvf nginx-1.18.0.tar.gz\ntar -xvf nginx_devel_kit.tar.gz\ntar -xvf nginx_lua_module.tar.gz\n```\n\n###### 5. Install luarocks from source\n\n```sh\ncd /tmp/nginx/luarocks-3.5.0\n./configure\nmake\nmake install\n```\n\n###### 6. Install Nettle from source\n\n```sh\ncd /tmp/nginx/nettle-3.6\n./configure --prefix=/usr --disable-static\nmake\nmake check\nmake install\n```\n\n###### 7. Install LuaJIT\n\n```\ncd /tmp/nginx/LuaJIT-2.0.5\nmake install\n```\n\n###### 8. Build and Install NGINX with required Modules\n\n```sh\ncd /tmp/nginx/nginx-1.18.0\nLUAJIT_LIB=/usr/local/lib LUAJIT_INC=/usr/local/include/luajit-2.0 \\\n./configure \\\n--user=nginx                          \\\n--group=nginx                         \\\n--prefix=/etc/nginx                   \\\n--sbin-path=/usr/sbin/nginx           \\\n--conf-path=/etc/nginx/nginx.conf     \\\n--pid-path=/var/run/nginx.pid         \\\n--lock-path=/var/run/nginx.lock       \\\n--error-log-path=/var/log/nginx/error.log \\\n--http-log-path=/var/log/nginx/access.log \\\n--with-http_gzip_static_module        \\\n--with-http_stub_status_module        \\\n--with-debug                          \\\n--with-http_ssl_module                \\\n--with-pcre                           \\\n--with-http_perl_module               \\\n--with-file-aio                       \\\n--with-http_realip_module             \\\n--add-module=/tmp/nginx/ngx_devel_kit-0.3.1 \\\n--add-module=/tmp/nginx/lua-nginx-module-0.10.15\nmake install\n```\n\n###### 9. Install PerimeterX Nginx Plugin \u0026 Dependencies\n\n```sh\nluarocks install luasec\nluarocks install lustache\nluarocks install lua-resty-core\nluarocks install lua-resty-nettle\nluarocks install luasocket\nluarocks install lua-resty-http\nluarocks install lua-cjson\nluarocks install perimeterx-nginx-plugin\n```\n\n###### 10. Optionally, if you are testing in a new environment you may need to configure the following:\n\n- Add the user \"nginx\"\n\n  ```sh\n  sudo useradd --system --home /var/cache/nginx --shell /sbin/nologin --comment \"nginx user\" --user-group nginx\n  ```\n\n- Create a systemd service for NGINX\n\n  ```sh\n  sudo vi /usr/lib/systemd/system/nginx.service\n  ```\n\n- Paste the following in the file you just created:\n\n  ```text\n  [Unit]\n  Description=nginx - high performance web server\n  Documentation=https://nginx.org/en/docs/\n  After=network-online.target remote-fs.target nss-lookup.target\n  Wants=network-online.target\n\n  [Service]\n  Type=forking\n  PIDFile=/var/run/nginx.pid\n  ExecStartPre=/usr/sbin/nginx -t -c /etc/nginx/nginx.conf\n  ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf\n  ExecReload=/bin/kill -s HUP $MAINPID\n  ExecStop=/bin/kill -s TERM $MAINPID\n\n  [Install]\n  WantedBy=multi-user.target\n  ```\n\n- Enable and Start the NGINX Service\n  ```sh\n  sudo systemctl is-enabled nginx.service\n  sudo systemctl start nginx.service\n  sudo systemctl enable nginx.service\n  ```\n\n### \u003ca name=\"installation_nginxplus_px\"\u003e\u003c/a\u003eInstalling the PerimeterX NGINX Plugin for NGINX+\n\nIf you are already using NGINX+, the following steps cover installing the NGINX+ Lua Module and the PermimeterX NGINX Plugin.\n\n- [RHEL 7.4 and higher](NGINXPLUS_RHEL7.4.md)\n- [Amazon Linux, CentOS and RHEL 7.3 and lower](NGINXPLUS.md)\n\n## \u003ca name=\"configuration\"\u003e\u003c/a\u003eConfiguration\n\n### \u003ca name=\"nginx_configuration\"\u003e\u003c/a\u003eRequired NGINX Configuration\n\nThe following NGINX Configurations are required to support the PerimeterX NGINX Lua Plugin:\n\n- #### \u003ca name=\"nginx_resolver\"\u003e\u003c/a\u003eResolver\n\n  The Resolver directive must be configured in the HTTP section of your NGINX configuration, IPv6 addresses are not supported.\n\n  - Set the resolver, `resolver A.B.C.D;`, to an external DNS resolver, such as Google (`resolver 8.8.8.8 ipv6=off;`),\n\n  _or_\n\n  - Set the resolver, `resolver A.B.C.D;`, to the internal IP address of your DNS resolver (`resolver 10.1.1.1 ipv6=off;`).\n\n  This is required for NGINX to resolve the PerimeterX API.\n\n- #### \u003ca name=\"nginx_lua_package_path\"\u003e\u003c/a\u003eLua Package Path\n\n  Ensure your Lua package path location in the HTTP section of your configuration reflects the location of the installed PerimeterX modules.\n\n  ```\n  lua_package_path \"/usr/local/lib/lua/?.lua;;\";\n  ```\n\n- #### \u003ca name=\"nginx_lua_ca_certificates\"\u003e\u003c/a\u003eLua CA Certificates\n\n  For TLS support to PerimeterX servers, configure Lua to point to the trusted certificate location.\n\n  ```\n  lua_ssl_trusted_certificate \"/etc/ssl/certs/ca-certificates.crt\";\n  lua_ssl_verify_depth 3;\n  ```\n\n  \u003e NOTE: The certificate location may differ between Linux distributions. In CentOS/RHEL systems, the CA bundle location may be located at `/etc/pki/tls/certs/ca-bundle.crt`.\n\n- #### \u003ca name=\"nginx_lua_timer_initialization\"\u003e\u003c/a\u003eLua Timer Initialization\n\n  Add the init with a Lua script. The init is used by PerimeterX to hold and send metrics at regular intervals.\n\n  ```\n  init_worker_by_lua_block {\n      local pxconfig = require(\"px.pxconfig\")\n      require (\"px.utils.pxtimer\").application(pxconfig)\n  }\n  ```\n\n- #### \u003ca name=\"nginx_perimeterx_enforcement\"\u003e\u003c/a\u003eApply PerimeterX Enforcement\n\n  Add the following lines to your `location` block:\n\n  ```\n  #----- PerimeterX protect location -----#\n  access_by_lua_block {\n    local pxconfig = require(\"px.pxconfig\")\n    require (\"px.pxnginx\").application(pxconfig)\n  }\n  header_filter_by_lua_block {\n    require(\"px.pxnginx\").finalize()\n  }\n  #----- PerimeterX Module End  -----#\n  ```\n\n- #### \u003ca name=\"nginx_config_example\"\u003e\u003c/a\u003e nginx.conf Example\n\n  The following **nginx.conf** example contains the required directives with enforcement applied to the `location` block.\n\n  ```lua\n  worker_processes  1;\n  error_log /var/log/nginx/error.log;\n  events {\n      worker_connections 1024;\n  }\n\n  http {\n      lua_package_path \"/usr/local/lib/lua/?.lua;;\";\n\n      # -- initializing the perimeterx module -- #\n      init_worker_by_lua_block {\n          local pxconfig = require(\"px.pxconfig\")\n          require (\"px.utils.pxtimer\").application(pxconfig)\n      }\n\n      lua_ssl_trusted_certificate \"/etc/ssl/certs/ca-certificates.crt\";\n      lua_ssl_verify_depth 3;\n\n      resolver 8.8.8.8;\n\n      server {\n          listen 80;\n\n          location / {\n              #----- PerimeterX protect location -----#\n              access_by_lua_block {\n                local pxconfig = require(\"px.pxconfig\")\n                require(\"px.pxnginx\").application(pxconfig)\n              }\n              header_filter_by_lua_block {\n                require(\"px.pxnginx\").finalize()\n              }\n              #----- PerimeterX Module End  -----#\n\n              root   /nginx/www;\n              index  index.html;\n          }\n      }\n  }\n  ```\n\n\u003e NOTE: The NGINX Configuration Requirements must be completed before proceeding to the next stage of installation.\n\n### \u003ca name=\"configuration\"\u003e\u003c/a\u003ePerimeterX Plugin Configuration\n\n#### \u003ca name=\"perimterx_required_parameters\"\u003e\u003c/a\u003eRequired Configuration:\n\nThe following configurations are set in:\n\n**`/usr/local/lib/lua/px/pxconfig.lua`**\n\n```lua\n -- ## Required Parameters ##\n _M.px_appId = 'PX_APP_ID'\n _M.auth_token = 'PX_AUTH_TOKEN'\n _M.cookie_secret = 'COOKIE_ENCRYPTION_KEY'\n```\n\n- The PerimeterX **Application ID / AppId** and PerimeterX **Token / Auth Token** can be found in the Portal, in \u003ca href=\"https://console.perimeterx.com/#/app/applicationsmgmt\" onclick=\"window.open(this.href); return false;\"\u003e**Applications**\u003c/a\u003e.\n\n- PerimeterX **Cookie Encryption Key** can be found in the portal, in \u003ca href=\"https://console.perimeterx.com/#/app/policiesmgmt\" onclick=\"window.open(this.href); return false;\"\u003e**Policies**\u003c/a\u003e.\n\nThe Policy from where the **Cookie Encryption Key** is taken must correspond with the Application from where the **Application ID / AppId** and PerimeterX **Token / Auth Token**\n\n#### \u003ca name=\"first_party_config\"\u003e\u003c/a\u003e First-Party Configuration\n\n##### \u003ca name=\"first-party\"\u003e\u003c/a\u003e First-Party Mode\n\nFirst-Party Mode enables the module to send/receive data to/from the sensor, acting as a reverse-proxy for client requests and sensor activities.\n\nFirst-Party Mode may require additional changes on the [JS Sensor Snippet](#perimterx_first_party_js_snippet). For more information, refer to the PerimeterX Portal.\n\n```lua\n...\n_M.first_party_enabled = true\n```\n\nThe following routes must be enabled for First-Party Mode for the PerimeterX Lua module: - `/\u003cPX_APP_ID without PX prefix\u003e/xhr/*` - `/\u003cPX_APP_ID without PX prefix\u003e/init.js`\n\n- If the PerimeterX Lua module is enabled on `location /`, the routes are already open and no action is necessary.\n\n- If the PerimeterX Lua module is _not_ enabled on `location /`, add to your server block for NGINX:\n\n```lua\nserver {\n    listen 80;\n\n    location /\u003cPX_APP_ID without PX prefix\u003e {\n        #----- PerimeterX protect location -----#\n        access_by_lua_block {\n          local pxconfig = require(\"px.pxconfig\")\n          require(\"px.pxnginx\").application(pxconfig)\n        }\n        header_filter_by_lua_block {\n         require(\"px.pxnginx\").finalize()\n        }\n        #----- PerimeterX Module End  -----#\n\n        root   /nginx/www;\n        index  index.html;\n    }\n}\n```\n\n\u003e NOTE: If your NGINX version supports HTTP v2, refer to the [HTTP v2 section of the Appendix](#http2).\n\n\u003e NOTE: The PerimeterX NGINX Lua Plugin Configuration Requirements must be completed before proceeding to the next stage of installation.\n\n##### \u003ca name=\"perimterx_first_party_js_snippet\"\u003e\u003c/a\u003e First-Party JS Snippet\n\nEnsure the [PerimeterX NGINX Lua Plugin](#perimterx_plugin_configuration) is configured before deploying the PerimeterX First-Party JS Snippet across your site. (Detailed instructions for deploying the PerimeterX First-Party JS Snippet can be found \u003ca href=\"https://docs.perimeterx.com/pxconsole/docs/managing-applications#section-snippet\" onclick=\"window.open(this.href); return false;\"\u003ehere\u003c/a\u003e.)\n\nTo deploy the PerimeterX First-Party JS Snippet:\n\n##### 1. Generate the First-Party Snippet\n\n- Go to \u003ca href=\"https://console.perimeterx.com/#/app/applicationsmgmt\" onclick=\"window.open(this.href); return false;\"\u003e**Applications**\u003c/a\u003e \u003e\u003e **Snippet**.\n- Select **First-Party**.\n- Select **Use Default Routes**.\n- Click **Copy Snippet** to generate the JS Snippet.\n\n##### 2. Deploy the First-Party Snippet\n\n- Copy the JS Snippet and deploy using a tag manager, or by embedding it globally into your web template for which websites you want PerimeterX to run.\n\n## \u003ca name=\"advanced_configuration\"\u003e\u003c/a\u003e Optional Configuration\n\n### \u003ca name=\"monitoring_mode\"\u003e\u003c/a\u003eMonitor / Block Mode Configuration\n\nBy default, the PerimeterX plugin is set to Monitor Only mode (`_M.block_enabled = false`).\n\nAdding the **\\_ M.block_enabled** flag and setting it to _true_ in the `pxconfig.lua` file activates the module to enforce blocking.\n\nThe PerimeterX Module blocks requests that exceed the block score threshold. If a request receives a risk score that is equal to or greater than the block score, a block page is displayed.\n\n### \u003ca name=\"debug-mode\"\u003e\u003c/a\u003e Debug Mode\n\nEnables debug logging mode.\n\n**Default:** false (disabled)\n\n```\n_M.px_debug = true\n```\n\nWhen Enabled, PerimeterX debug messages should be in the following template:\n\n- For debug messages - `[PerimeterX - DEBUG] [APP_ID] - MESSAGE` \u003cbr /\u003e\n- For error messages - `[PerimeterX - ERROR] [APP_ID] - MESSAGE`\n\nValid request flow example:\n\n```\n2017/12/04 12:04:18 [error] 7#0: *9 [lua] pxlogger.lua:29: debug(): [PerimeterX - DEBUG] [ APP_ID ] - Cookie V3 found - Evaluating, client: 172.17.0.1, server: , request: \"GET / HTTP/1.1\", host: \"localhost:8888\"\n2017/12/04 12:04:18 [error] 7#0: *9 [lua] pxlogger.lua:29: debug(): [PerimeterX - DEBUG] [ APP_ID ] - cookie is encyrpted, client: 172.17.0.1, server: , request: \"GET / HTTP/1.1\", host: \"localhost:8888\"\n2017/12/04 12:04:18 [error] 7#0: *9 [lua] pxlogger.lua:29: debug(): [PerimeterX - DEBUG] [ APP_ID ] - Cookie evaluation ended successfully, risk score: 0, client: 172.17.0.1, server: , request: \"GET / HTTP/1.1\", host: \"localhost:8888\"\n2017/12/04 12:04:18 [error] 7#0: *9 [lua] pxlogger.lua:29: debug(): [PerimeterX - DEBUG] [ APP_ID ] - Sent page requested acitvity, client: 172.17.0.1, server: , request: \"GET / HTTP/1.1\", host: \"localhost:8888\"\n2017/12/04 12:04:18 [error] 7#0: *9 [lua] pxlogger.lua:29: debug(): [PerimeterX - DEBUG] [ APP_ID ] - Request is internal. PerimeterX processing skipped., client: 172.17.0.1, server: , request: \"GET / HTTP/1.1\", host: \"localhost:8888\"\n2017/12/04 12:04:19 [error] 7#0: *63 [lua] pxlogger.lua:29: debug(): [PerimeterX - DEBUG] [ APP_ID ] - POST response status: 200, context: ngx.timer\n2017/12/04 12:04:19 [error] 7#0: *63 [lua] pxlogger.lua:29: debug(): [PerimeterX - DEBUG] [ APP_ID ] - Reused conn times: 3, context: ngx.timer\n```\n\n### \u003ca name=\"whitelisting\"\u003e\u003c/a\u003e Whitelisting\n\nWhitelisting (bypassing enforcement) is configured in the `pxconfig.lua` file\n\nSeveral filters can be configured:\n\n```javascript\n   _M.whitelist_uri_full = { _M.custom_block_url },\n   _M.whitelist_uri_prefixes = {},\n   _M.whitelist_uri_suffixes = {'.css', '.bmp', '.tif', '.ttf', '.docx', '.woff2', '.js', '.pict', '.tiff', '.eot', '.xlsx', '.jpg', '.csv', '.eps', '.woff', '.xls', '.jpeg', '.doc', '.ejs', '.otf', '.pptx', '.gif', '.pdf', '.swf', '.svg', '.ps', '.ico', '.pls', '.midi', '.svgz', '.class', '.png', '.ppt', '.mid', '.webp', '.jar'},\n   _M.whitelist_uri_pattern = {},\n   _M.whitelist_ip_addresses = {},\n   _M.whitelist_ua_full = {},\n   _M.whitelist_ua_sub = {}\n```\n\n| Filter Name                | Value                                                                | Filters Request To                                                         |\n| -------------------------- | -------------------------------------------------------------------- | -------------------------------------------------------------------------- |\n| **whitelist_uri_full**     | `{'/api_server_full'}`                                               | `/api_server_full?data=1` \u003c/br\u003e but not to \u003c/br\u003e `/api_server?data=1`      |\n| **whitelist_uri_prefixes** | `{'/api_server'}`                                                    | `/api_server_full?data=1` \u003c/br\u003e but not to \u003c/br\u003e `/full_api_server?data=1` |\n| **whitelist_uri_suffixes** | `{'.css'}`                                                           | `/style.css` \u003c/br\u003e but not to \u003c/br\u003e `/style.js`                            |\n| **whitelist_uri_pattern**  | `{'/api/.*/server'}`                                                 | `/api/any/thing/server?data=1` \u003c/br\u003e but not to \u003c/br\u003e `/api/api_server`    |\n| **whitelist_ip_addresses** | `{'192.168.99.1'}`                                                   | Filters requests coming from any of the listed IPs.                        |\n| **whitelist_ua_full**      | `{'Mozilla/5.0 (compatible; pingbot/2.0; http://www.pingdom.com/)'}` | Filters all requests matching this exact UA.                               |\n| **whitelist_ua_sub**       | `{'GoogleCloudMonitoring'}`                                          | Filters requests containing the provided string in their UA.               |\n\n### \u003ca name=\"sensitive-headers\"\u003e\u003c/a\u003e Filter Sensitive Headers\n\nA list of sensitive headers configured to prevent specific headers from being sent to PerimeterX servers (headers in lower case). Filtering cookie headers for privacy is set by default, and can be overridden on the `pxConfig` variable.\n\n**Default:** cookie, cookies\n\nExample:\n\n```lua\n_M.sensitive_headers = {'cookie', 'cookies', 'secret-header'}\n```\n\n### \u003ca name=\"enabled-routes\"\u003e\u003c/a\u003e Enabled Routes\n\nAllows you to define a set of routes on which the plugin will be active. An empty list sets all routes in the application as active.\n\n**Default:** Empty list (all routes are active)\n\nExample:\n\n```lua\n _M.enabled_routes = {'/blockhere'}\n```\n\n### \u003ca name=\"custom-enabled-routes\"\u003e\u003c/a\u003e Custom Enabled Routes\n\nAllows you to define a function, which takes `uri` as an argument and returns `true` or `false`.\nReturning `true` means that the plugin will be active for the given `uri`.\n\n**Default:** Function is not defined (all routes are active)\n\nExample:\n\n```lua\n-- return `true` if `/tmp/urls.txt` contains a string matching `uri`\n-- Warning! Reading from a file for each request could affect performance!\n_M.custom_enabled_routes = function(uri)\n    for line in io.lines(\"/tmp/urls.txt\") do\n        -- simple substring match, could be extended to a pattern matching\n        if string.sub(uri, 1, string.len(line)) == line then\n            return true\n        end\n    end\n    return false\nend\n\n```\nSee [examples/custom_enabled_routes.lua](/examples/custom_enabled_routes.lua) for a complete example of using `custom_enabled_routes`.\n\n\n### \u003ca name=\"monitored-routes\"\u003e\u003c/a\u003e Monitored Routes\n\nallows you to define a set of route prefixes that will be handled as if in monitor mode, even if `block_enabled` is set to `true`.\n\n**Default:** Empty list\n\nExample:\n\n```lua\n _M.monitored_routes = {'/profile'}\n```\n\n### \u003ca name=\"sensitive-routes\"\u003e\u003c/a\u003e Sensitive Routes\n\nA list of route prefixes and suffixes. The PerimeterX module always matches the request URI with the prefixes list and suffixes list. When there is a match, the PerimeterX module creates a server-to-server call, even when the cookie is valid and the risk score is low.\n\n**Default:** Empty list\n\nExample:\n\n```lua\n_M.sensitive_routes_prefix = {'/login', '/user/profile'}\n_M.sensitive_routes_suffix = {'/download'}\n```\n\n### \u003ca name=\"sensitive-routes-regex\"\u003e\u003c/a\u003e Sensitive Routes Regex List\nA list of route regular expressions (regex). When PerimeterX module matches the request URI with a regex from the list, the module creates a server-to-server call, even when the cookie is valid and the risk score is low.\n\n**Default:** Empty list\n\nExample:\n\n```lua\n_M.sensitive_routes = {'^/login/[0-9]*user$'}\n```\n\n### \u003ca name=\"custom-sensitive-routes\"\u003e\u003c/a\u003e Custom Sensitive Routes\nAllows you to define a function, which takes `uri` as an argument and returns `true` or `false`.\nReturning `true` means that PerimeterX module creates a server-to-server call, even when the cookie is valid and the risk score is low.\n\n**Default:** Function is not defined\n\nExample:\n\n```lua\n-- return `true` if `/tmp/urls.txt` contains a string matching `uri`\n-- Warning! Reading from a file for each request could affect performance!\n_M.custom_sensitive_routes = function(uri)\n    for line in io.lines(\"/tmp/urls.txt\") do\n        -- simple substring match, could be extended to a pattern matching\n        if string.sub(uri, 1, string.len(line)) == line then\n            return true\n        end\n    end\n    return false\nend\n\n```\nSee [examples/custom_enabled_routes.lua](/examples/custom_enabled_routes.lua) for a complete example of using `custom_enabled_routes` (which is similar to `custom_sensitive_routes`).\n\n\n### \u003ca name=\"api-timeout\"\u003e\u003c/a\u003eAPI Timeout Milliseconds\n\nAPI Timeout in milliseconds (float) to wait for the PerimeterX server API response.\u003c/br\u003e\nControls the timeouts for PerimeterX requests. The API is called when a Risk Cookie does not exist, is expired, or is invalid.\n\n**Default:** 1000\n\nExample:\n\n```\n _M.s2s_timeout = 250\n```\n\n### \u003ca name=\"customblockpage\"\u003e\u003c/a\u003e Customize Default Block Page\n\nThe PerimeterX default block page can be modified by injecting custom CSS, JavaScript and a custom logo to the block page.\n\n**Default:** nil\n\nExample:\n\n```\n_M.custom_logo = \"http://www.example.com/logo.png\"\n_M.css_ref = \"http://www.example.com/style.css\"\n_M.js_ref = \"http://www.example.com/script.js\"\n```\n\n### \u003ca name=\"redirect_to_custom_blockpage\"\u003e\u003c/a\u003eRedirect to a Custom Block Page URL\n\nCustomizes the block page to meet branding and message requirements by specifying the URL of the block page HTML file. The page can also implement CAPTCHA.\n\n**Default:** nil\n\nExample:\n\n```lua\n_M.custom_block_url = '/block.html'\n```\n\n\u003e Note: This URI is whitelisted automatically under `_M.Whitelist['uri_full'] ` to avoid infinite redirects.\n\n### \u003ca name=\"redirect_on_custom_url\"\u003e\u003c/a\u003e Redirect on Custom URL\n\nThe `_M.redirect_on_custom_url` boolean flag to redirect users to a block page.\n\n**Default:** false\n\nExample:\n\n```lua\n  _M.redirect_on_custom_url = false\n```\n\nBy default, when a user exceeds the blocking threshold and blocking is enabled, the user is redirected to the block page defined by the `_M.custom_block_url` variable. The defined block page displays a **307 (Temporary Redirect)** HTTP Response Code.\n\nWhen the flag is set to false, a **403 (Unauthorized)** HTTP Response Code is displayed on the blocked page URL. \u003c/br\u003e\nSetting the flag to true (enabling redirects) results in the following URL upon blocking:\n\n```\n http://www.example.com/block.html?url=L3NvbWVwYWdlP2ZvbyUzRGJhcg==\u0026uuid=e8e6efb0-8a59-11e6-815c-3bdad80c1d39\u0026vid=08320300-6516-11e6-9308-b9c827550d47\n```\n\nSetting the flag to false does not require the block page to include any of the examples below, as they are injected into the blocking page via the PerimeterX NGINX Enforcer.\n\n\u003e NOTE: The URL variable should be built with the URL Encoded query parameters (of the original request) with both the original path and variables Base64 Encoded (to avoid collisions with block page query params).\n\n#### Custom Block Pages Requirements\n\nAs of version 4.0, Captcha logic is being handled through the JavaScript snippet and not through the Enforcer.\n\nUsers who have Custom Block Pages must include the new script tag and a new div in the _.html_ block page. For implementation instructions refer to the appropriate links below:\n\n- [reCaptcha](examples/Custom Block Page + reCAPTCHA + Redirect/README.md)\n- [Custom Block Page](examples/Custom Block Page/README.md)\n\n### \u003ca name=\"redirect_to_referer\"\u003e\u003c/a\u003e Redirect to Referer\n\nIndicates whether the user is redirected from the challenge page to the referrer page after successfully solving the challenge.\n\n**Default:** false\n\nExample:\n\n```lua\n_M.redirect_to_referer = true\n```\n\n### \u003ca name=\"add-activity-handler\"\u003e\u003c/a\u003e Additional Activity Handler\n\nAn additional activity handler is added by setting `_M.additional_activity_handler` with a user defined function in the 'pxconfig.lua' file.\n\n**Default:** Activity is sent to PerimeterX as controlled by 'pxconfig.lua'.\n\nExample:\n\n```lua\n_M.additional_activity_handler = function(event_type, ctx, details)\n local cjson = require \"cjson\"\n if (event_type == 'block') then\n   logger.warning(\"PerimeterX \" + event_type + \" blocked with score: \" + ctx.blocking_score + \"details \" + cjson.encode(details))\n else\n   logger.info(\"PerimeterX \" + event_type + \" details \" +  cjson.encode(details))\n end\nend\n```\n\n### \u003ca name=\"custom-parameters\"\u003e Enrich Custom Parameters\n\nWith the `enrich_custom_params` function you can add up to 10 custom parameters to be sent back to PerimeterX servers. When set, the function is called before setting the payload on every request to PerimeterX servers. The parameters should be passed according to the correct order (1-10).\nYou must return the `px_custom_params` object at the end of the function.\n\n**Default:** nil\n\nExample:\n\n```lua\n_M.enrich_custom_parameters = function(px_custom_params)\n  px_custom_params[\"custom_param1\"] = \"user_id\"\n  return px_custom_params\nend\n```\n\n### \u003ca name=\"blocking-score\"\u003e\u003c/a\u003e Changing the Minimum Score for Blocking\n\nThis value should not be changed from the default of 100 unless advised by PerimeterX.\n\n**Default blocking value:** 100\n\nExample:\n\n```lua\n  _M.blocking_score = 100\n```\n\n### \u003ca name=\"first-party-prefix\"\u003e\u003c/a\u003e First-Party Prefix\n\nAllows you to define a custom prefix for First-Party routes. Refer to [Setting Up A First Party Prefix](FIRST_PARTY_PREFIX.md) for complete setup instructions.\n\n**Default:** nil\n\nExample:\n\n```lua\n_M.first_party_prefix = 'resources'\n```\n\n### \u003ca name=\"json-response-enabled\"\u003e\u003c/a\u003e Advanced Blocking Response Support\n\nEnables/disables support for [Advanced Blocking Response](#advancedBlockingResponse).\n\n**Default:** true (enabled)\n\nExample:\n\n```lua\n_M.advanced_blocking_response = false\n```\n\n### \u003ca name=\"proxy-support\"\u003e\u003c/a\u003e Proxy Support\n\nSets a proxy server for all the enforcer's outgoing calls.\n\n\u003e Requires `lua-resty-http` version 0.12 and up.\n\n**Default:** nil\n\nExample:\n\n```lua\n_M.proxy_url = 'http://localhost:8008'\n```\n\n### \u003ca name=\"proxy-authorization\"\u003e\u003c/a\u003e Proxy Authorization\n\nIf proxy support is enabled, allow you to set a proxy authorization header.\n\n\u003e Requires `lua-resty-http` version 0.12 and up.\n\n**Default:** nil\n\nExample:\n\n```lua\n_M.proxy_authorization = 'top-secret-header-value'\n```\n\n#### \u003ca name=\"custom-cookie-header\"\u003e\u003c/a\u003e Custom Cookie Header\n\nWhen set, this property specifies a header name which will be used to extract the PerimeterX cookie from, instead of the Cookie header.\n\n\u003e NOTE: Using a custom cookie header requires client side integration to be done as well. Please refer to the relevant [docs](https://docs.perimeterx.com/pxconsole/docs/advanced-client-integration#section-custom-cookie-header) for details.\n\n**Default:** nil\n\nExample:\n\n```lua\n_M.custom_cookie_header = 'x-px-cookies'\n```\n\n#### \u003ca name=\"bypass-monitor-header\"\u003e\u003c/a\u003e Bypass Monitor Mode Header\n\nWhen set, allows you to test the blocking flow of an enforcer, while in monitoring mode. \u003cbr/\u003e\nThe property accept an header name which, if provided in a request with the value of `1`, in addition to a bad user agent (such as `PhantomJS/1.0`) will block the request and show a challenge page.\n\n**Default:** nil\n\n```lua\n_M.bypass_monitor_header = 'x-px-block'\n```\n\n#### \u003ca name=\"pxhd-cookie\"\u003e\u003c/a\u003e Secured PXHD Cookie\n\nA boolean flag to enable/disable the `Secure` flag when baking a PXHD cookie.\n\n**Default:** false\n\n```lua\n_M.pxhd_secure_enabled = true\n```\n\n## \u003ca name=\"enrichment\"\u003e\u003c/a\u003e Enrichment\n\n### \u003ca name=\"data-enrichment\"\u003e\u003c/a\u003e Data Enrichment\n\nThe PerimeterX NGINX plugin stores the data enrichment payload on the request context. The data enrichment payload can also be processed with `additional_activity_handler`.\n\nOnly requests that are _not_ being block will reach the backend server, so specific logic must be applied to the processing function.\n\nThe following example includes the pre-condition checks required to process the data enrichment payload and enrich the request headers.\n\n```lua\n    ...\n    _M.additional_activity_handler = function(event_type, ctx, details)\n        -- verify that the request is passed to the backend\n        if event_type == 'page_requested' then\n          -- pxde - contains a parsed json of the data enrichment object\n          -- pxde_verified - makes sure that this payload is trusted and signed by PerimeterX\n          local pxde = ngx.ctx.pxde\n          local pxde_verified = ngx.ctx.pxde_verified\n          if pxde and pxde_verified then\n              -- apply the data enrichment logic here\n              -- the example below will set the f_type on the request header\n              local f_type = ngx.ctx.pxde.f_type\n              ngx.req.set_header(\"x-px-de-f-type\", f_type)\n          end\n        end\n    end\n    ...\n```\n\nFor more information and the available fields in the JSON, refer to the [PerimeterX Portal documentation](https://docs.perimeterx.com/pxconsole/docs/data-enrichment).\n\n### \u003ca name=\"log-enrichment\"\u003e\u003c/a\u003e Log Enrichment\n\nAccess logs can be enriched with the PerimeterX bot information by creating an NGINX variable with the proper name. To configure this variable use the NGINX map directive in the HTTP section of your NGINX configuration file. This should be added before additional configuration files are added.\n\n**The following variables are enabled:**\n\n- **Request UUID**: `pxuuid`\n- **Request VID**: `pxvid`\n- **Risk Round Trimp**: `pxrtt`\n- **Risk Score**: `pxscore`\n- **Pass Reason**: `pxpass`\n- **Block Reason**: `pxblock`\n- **Cookie Validity**: `pxcookiets`\n- **Risk Call Reason**: `pxcall`\n\n```lua\n....\nhttp {\n    map score $pxscore  { default 'none'; }\n    map pass $pxpass  { default 'none'; }\n    map uuid $pxuuid  { default 'none'; }\n    map rtt $pxrtt { default '0'; }\n    map block $pxblock { default 'none'; }\n    map vid $pxvid { default 'none'; }\n    map cookiets $pxcookiets { default 'none'; }\n    map px_call $pxcall { default 'none'; }\n\n    log_format enriched '$remote_addr - $remote_user [$time_local] '\n                    '\"$request\" $status $body_bytes_sent '\n                    '\"$http_referer\" \"$http_user_agent\" '\n                    '| perimeterx uuid[$pxuuid] vid[$pxvid] '\n                    'score[$pxscore] rtt[$pxrtt] block[$pxblock] '\n                    'pass[$pxpass] cookie_ts[$pxcookiets] risk_call[$pxcall]';\n\n    access_log /var/log/nginx/access_log enriched;\n\n  }\n  ...\n```\n\n## \u003ca name=\"advancedBlockingResponse\"\u003e\u003c/a\u003e Advanced Blocking Response\n\nIn special cases, (such as XHR post requests) a full Captcha page render might not be an option. In such cases, using the Advanced Blocking Response returns a JSON object containing all the information needed to render your own Captcha challenge implementation, be it a popup modal, a section on the page, etc. The Advanced Blocking Response occurs when a request contains the _Accept_ header with the value of `application/json`. A sample JSON response appears as follows:\n\n```javascript\n{\n    \"appId\": String,\n    \"jsClientSrc\": String,\n    \"firstPartyEnabled\": Boolean,\n    \"vid\": String,\n    \"uuid\": String,\n    \"hostUrl\": String,\n    \"blockScript\": String\n}\n```\n\nOnce you have the JSON response object, you can pass it to your implementation (with query strings or any other solution) and render the Captcha challenge.\n\nIn addition, you can add the `_pxOnCaptchaSuccess` callback function on the window object of your Captcha page to react according to the Captcha status. For example when using a modal, you can use this callback to close the modal once the Captcha is successfully solved. \u003cbr/\u003e An example of using the `_pxOnCaptchaSuccess` callback is as follows:\n\n```javascript\nwindow._pxOnCaptchaSuccess = function (isValid) {\n  if (isValid) {\n    alert(\"yay\");\n  } else {\n    alert(\"nay\");\n  }\n};\n```\n\nFor details on how to create a custom Captcha page, refer to the [documentation](https://docs.perimeterx.com/pxconsole/docs/customize-challenge-page)\n\n## \u003ca name=\"loginCredentialsExtraction\"\u003e\u003c/a\u003e Login Credentials Extraction\n\nThis feature extracts credentials (hashed username and password) from requests and sends them to PerimeterX as additional info in risk / activity api calls. The feature can be toggled on and off. The settings are adjusted by modifying a Credentials JSON file.\n\n\n### \u003ca name=\"loginCredentialsExtractionConfiguration\"\u003e\u003c/a\u003e Login Credentials Extraction Configuration\n\n### \u003ca name=\"px_enable_login_creds_extraction\"\u003e\u003c/a\u003e Enable Login Credentials Extraction\nEnables Login Credentials Extraction\n\n**Default:** false (disabled)\n\n```\n_M.px_enable_login_creds_extraction = true\n```\n\n### \u003ca name=\"px_login_creds_settings_filename\"\u003e\u003c/a\u003e Credentials JSON file\nSets a full path to credentials JSON file\n\n**Default:** nil (none)\n\n```\n_M.px_login_creds_settings_filename = '/etc/creds.json'\n```\n\nExample available in `examples/creds.json` file. It includes an array of JSON objects containing the following properties:\n\n```json5\n{\n  \"id\": 0, // unique int\n  \"method\": \"post\", // supported methods: post\n  \"sent_through\": \"body\", // supported sent_throughs: header, url, body\n  \"path\": \"/login\", // login path\n  \"pass_field\": \"password\", // name of the password field in the request\n  \"user_field\": \"username\" // name of the username field in the request\n}\n```\n\n### \u003ca name=\"px_credentials_intelligence_version\"\u003e\u003c/a\u003e Credentials Intelligence Version\nSets Credentials Intelligence protocol version\n\n**Default:** 'v1'\n\n```\n_M.px_credentials_intelligence_version = 'v1'\n```\n\n### \u003ca name=\"px_additional_s2s_activity_header_enabled\"\u003e\u003c/a\u003e Additional s2s Activity Header\nEnables attaching additional s2s activity header ('px-additional-activity'), instead of sending Additional s2s activity to PX Collector.\n\n**Default:** false\n\n```\n_M.px_additional_s2s_activity_header_enabled = false\n```\n\n### \u003ca name=\"px_send_raw_username_on_additional_s2s_activity\"\u003e\u003c/a\u003e Send Raw Username On Additional s2s Activity\nEnables sending a raw username on additional s2s activity (only when activities are sent to PX Collector)\n\n**Default:** false\n\n```\n_M.px_send_raw_username_on_additional_s2s_activity = false\n```\n\n### \u003ca name=\"px_compromised_credentials_header_name\"\u003e\u003c/a\u003e Compromised Credentials Header Name\nCompromised credentials header name\n\n**Default:** 'x-px-compromised-credentials'\n\n```\n_M.px_compromised_credentials_header_name = 'x-px-compromised-credentials'\n```\n\n### \u003ca name=\"px_login_successful_reporting_method\"\u003e\u003c/a\u003e Login Successful Reporting Method\nSets login successful reporting method, could be one of the following values: 'none', 'header', 'status', 'custom'\n\n**Default:** 'none'\n\n```\n--_M.px_login_successful_reporting_method = 'none'\n```\n\n### \u003ca name=\"px_login_successful_header_name\"\u003e\u003c/a\u003e Login Successful Header Name\nSets login successful header name\n\n**Default:** 'x-px-login-successful'\n\n```\n_M.px_login_successful_header_name = \"x-px-login-successful\"\n```\n\n### \u003ca name=\"px_login_successful_header_value\"\u003e\u003c/a\u003e Login Successful Header Value\nSets login successful header value\n\n**Default:** '1'\n\n```\n_M.px_login_successful_header_value = \"1\"\n```\n\n### \u003ca name=\"px_login_successful_status\"\u003e\u003c/a\u003e Login Successful Status\nSets login successful status(-es)\n\n**Default:** { 200 }\n\n```\n_M.px_login_successful_status = { 200 }\n```\n\n### \u003ca name=\"custom_login_successful\"\u003e\u003c/a\u003e Login Successful Custom Function\nSets an user defined function which should return `true` if login was successful.\n\n**Default:** nil\n\n```\n_M.custom_login_successful = function()\n    local headers, err = ngx.resp.get_headers()\n    if err then\n        return false\n    end\n    if headers['x-login'] and headers['x-login'] == \"123\" then\n        return true\n    else\n        return false\n    end\nend\n```\n\n\n## \u003ca name=\"hypesale\"\u003e\u003c/a\u003e HypeSale\nTo enforcer will server the hypesale page in cases where the custom_param[\"is_hype_sale\"] set to true.\nIf the request contains a cookie `_px3` with the `cpa` value so the hypesale will not be served but the enforcer will do risk_api to verify the request.\n\n### \u003ca name=\"hypesale_host\"\u003e\u003c/a\u003e HypeSale host\nSets HypeSale host\n\n**Default:** 'https://captcha.px-cdn.net'\n\n```\n_M.hypesale_host = 'https://captcha.px-cdn.net'\n```\n\n\n## \u003ca name=\"graphql\"\u003e\u003c/a\u003e Sensitive GraphQL Operations\nFor those using GraphQL endpoints, it is possible to trigger server-to-server risk calls on particular operation types or names. Like the sensitive routes feature, a request that contains an operation of the configured type or name will trigger a server call to PerimeterX servers every time that operation is performed.\nNote: This feature only applies to requests that contain the string `graphql` somewhere in the path name.\n\n### \u003ca name=\"px_sensitive_graphql_operation_types\"\u003e\u003c/a\u003e Sensitive GraphQL Operation Types\nSets an operation type (e.g., query, mutation)\n\n**Default:** nil (none)\n\n```lua\n_M.px_sensitive_graphql_operation_types = {}\n```\n\n### \u003ca name=\"px_sensitive_graphql_operation_names\"\u003e\u003c/a\u003e Sensitive GraphQL Operation Names\nSets an operation name\n\n**Default:** nil (none)\n\n```lua\n_M.px_sensitive_graphql_operation_names = {}\n```\n\n### \u003ca name=\"px_sensitive_graphql_routes\"\u003e\u003c/a\u003e Sensitive GraphQL routes\n\nSets the list of one or more GraphQL routes.\n\nNote: the list contains Lua Patterns, more here: [Understanding Lua Patterns](https://www.fhug.org.uk/kb/kb-article/understanding-lua-patterns/)\n\n**Default:** `^/graphql/?$`\n\n```lua\n_M.px_graphql_routes = {\"^/graphql/?$\", \"^/graphql/csrf$\"}\n```\n\n\n## \u003ca name=\"appendix\"\u003e\u003c/a\u003e Appendix\n\n### \u003ca name=\"http2\"\u003e\u003c/a\u003e HTTP v2 Support\n\nThe PerimeterX NGINX module supports HTTP v2 for both Third-Party and First-Party implementations. To verify that your NGINX is running with HTTP v2 support, run:\n\n```\nnginx -V\n```\n\nFor NGINX modules that support HTTP v2, the flag `--with-http_v2_module` will be listed. For example:\n\n```\n# nginx -V\nnginx version: nginx/1.13.3\nbuilt by gcc 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.10)\nbuilt with OpenSSL 1.0.2g  1 Mar 2016\nTLS SNI support enabled\nconfigure arguments: --prefix=/nginx --with-ld-opt=-Wl,-rpath,/usr/local/lib --add-module=/ngx_devel_kit-0.3.0 --add-module=/lua-nginx-module-0.10.10 --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-ipv6 --with-http_v2_module\n```\n\nIf you are running in Third-Party mode, you do not need to take any additional actions for the PerimeterX NGINX module to support HTTP v2.\n\nIf you are running in First-Party mode, add the following location to your `nginx.conf` file:\n\n```\nlocation /\u003capp id without PX prefix\u003e/xhr/ {\n    proxy_buffering on;\n    proxy_buffer_size 128k;\n    proxy_buffers 4 256k;\n    proxy_busy_buffers_size 256k;\n    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n    proxy_set_header X-Forwarded-Host $server_name;\n    proxy_set_header X-PX-Enforcer-True-IP $remote_addr;\n    proxy_set_header X-PX-First-Party 1;\n    set $pxcookie \"\";\n    if ($cookie__pxvid != \"\") {\n        set $pxcookie pxvid=$cookie__pxvid;\n    }\n    if ($cookie_pxvid != \"\") {\n        set $pxcookie pxvid=$cookie_pxvid;\n    }\n    proxy_set_header cookie $pxcookie;\n    proxy_pass https://collector-\u003capp_id\u003e.perimeterx.net/;\n}\n```\n\n\u003e Note: Make sure you replace the \\\u003capp id without PX prefix\\\u003e and \\\u003capp_id\\\u003e with your PerimeterX appId value.\n\n### \u003ca name=\"nginxplus\"\u003e\u003c/a\u003e NGINX Plus\n\nThe PerimeterX NGINX module is compatible with NGINX Plus. Users or administrators should install the NGINX Plus Lua dynamic module (LuaJIT).\n\n### \u003ca name=\"dynamicmodules\"\u003e\u003c/a\u003e NGINX Dynamic Modules\n\nIf you are using NGINX with [dynamic module support](https://www.nginx.com/products/modules/) you can load the Lua module with the following lines at the beginning of your NGINX configuration file.\n\n```\nload_module modules/ndk_http_module.so;\nload_module modules/ngx_http_lua_module.so;\n```\n\n### \u003ca name=\"multipleapps\"\u003e\u003c/a\u003e Multiple App Support\n\nThe PerimeterX Enforcer allows multiple configurations for different applications.\n\nIf your PerimeterX account contains several applications (as defined in the Portal), you can create different configurations for each application.\n\n\u003e NOTE: The application initializes a timed Enforcer. The Enforcer must be initialized with one of the applications in your account. The the correct configuration file name must be passed to the `require (\"px.utils.pxtimer\").application(\"AppName\"|empty)` block in the server initialization.\n\n1. Open the `nginx.conf` file, and locate the `require(\"px.pxnginx\").application()` line inside your location block.\n2. Pass the desired application name into the `application()` function.\u003c/br\u003e\n   For example: `require(\"px.pxnginx\").application(\"mySpecialApp\")`\n3. Locate the `pxconfig.lua` file, and create a copy of it. \u003c/br\u003e The copy name should follow the pattern: \u003c/br\u003e `pxconfig-\u003cAppName\u003e.lua` (e.g. `pxconfig-mySpecialApp.lua`) \u003c/br\u003e The \u003c AppName \u003e placeholder must be replaced by the exact name provided to the application function in step 1.\n4. Change the configuration in file created in step 3.\n5. Save the file in the location where pxnginx.lua file is located.\n   (Default location: `/usr/local/lib/lua/px/\u003cyourFile\u003e`)\n6. For every location block of your app, replace the code mentioned in step 2 with the correct \u003c AppName \u003e.\n\n### \u003ca name=\"setting_up_first_party_prefix\"\u003e\u003c/a\u003e Setting Up A First Party Prefix\n\nDocumentation for setting up First-Party Prefixes is found [here](FIRST_PARTY_PREFIX.md).\n\n### \u003ca name=\"uri_delimiters\"\u003e\u003c/a\u003e URI Delimiters\n\nPerimeterX processes URI paths with general- and sub-delimiters according to RFC 3986. General delimiters (e.g., `?`, `#`) are used to separate parts of the URI. Sub-delimiters (e.g., `$`, `\u0026`) are not used to split the URI as they are considered valid characters in the URI path.\n\n## \u003ca name=\"test_environment\"\u003e\u003c/a\u003e Run test environment\n\nPerimeterX Nginx Lua Enforcer repository contains Dockerfile used to create a test docker image.\nIn order to build an image, the following files must be present in the project's \"example\" directory:\n* examples/pxconfig.lua - Enforcer configuration (`px_appId`, `cookie_secret` and `auth_token` parameters are required and must be set).\n* examples/nginx.conf - Nginx configuration\n* examples/creds.json - Credential Intelligence configuration (optional)\n\nWhen these files are present and adjusted, the following command could be executed from the project's root directory to run a test docker container: `./examples/run_docker.sh`\nDocker container will run and Nginx will listen on 8080 port.\n\n## \u003ca name=\"contributing\"\u003e\u003c/a\u003e Contributing\n\nThe following steps are welcome when contributing to our project.\n\n- ### Fork/Clone\n\n  [Create a fork](https://guides.github.com/activities/forking/) of the repository, and clone it locally.\n  Create a branch on your fork, preferably using a descriptive branch name.\n\n- ### \u003ca name=\"tests\"\u003e\u003c/a\u003eTest\n\n  Tests for this project are written using the [`Test::Nginx`](https://github.com/openresty/test-nginx) testing framework.\n\n  **Don't forget to test**.\n\n  This project relies heavily on tests to ensure that each user has the same experience, and no new features break the code. Before you create any pull request, make sure your project has passed all tests. If any new features require it, write your own test.\n\n  To run the tests\u003cbr/\u003e\n\n  1. Build the docker container.\n  2. Run the tests using the following command: make docker-test.\n\n- ### Pull Request\n  Once you have completed the process, create a pull request. Provide a complete and thorough description explaining the changes. Remember, the code has to be read by our maintainers, so keep it simple, smart and accurate.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fperimeterx%2Fperimeterx-nginx-plugin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fperimeterx%2Fperimeterx-nginx-plugin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fperimeterx%2Fperimeterx-nginx-plugin/lists"}