From ecb27521b411339d7cf9e9652d37b3e8174ed26c Mon Sep 17 00:00:00 2001 From: Stefano Badoino <16034687+SBado@users.noreply.github.com> Date: Wed, 23 Feb 2022 11:32:39 +0100 Subject: [PATCH 1/9] PROXY Protocol support implementation --- backend/internal/nginx.js | 3 +- .../20220209144645_proxy_protocol.js | 36 +++++++++++++++++++ backend/schema/endpoints/proxy-hosts.json | 28 +++++++++++++++ backend/templates/_listen.conf | 20 ++++++++--- backend/templates/_proxy_protocol.conf | 6 ++++ backend/templates/proxy_host.conf | 1 + frontend/js/app/nginx/proxy/form.ejs | 17 ++++++++- frontend/js/app/nginx/proxy/form.js | 14 +++++++- frontend/js/i18n/messages.json | 4 ++- frontend/js/models/proxy-host.js | 2 ++ 10 files changed, 122 insertions(+), 9 deletions(-) create mode 100644 backend/migrations/20220209144645_proxy_protocol.js create mode 100644 backend/templates/_proxy_protocol.conf diff --git a/backend/internal/nginx.js b/backend/internal/nginx.js index 52bdd66d..0291dfda 100644 --- a/backend/internal/nginx.js +++ b/backend/internal/nginx.js @@ -157,7 +157,8 @@ const internalNginx = { for (let i = 0; i < host.locations.length; i++) { let locationCopy = Object.assign({}, {access_list_id: host.access_list_id}, {certificate_id: host.certificate_id}, {ssl_forced: host.ssl_forced}, {caching_enabled: host.caching_enabled}, {block_exploits: host.block_exploits}, - {allow_websocket_upgrade: host.allow_websocket_upgrade}, {http2_support: host.http2_support}, + {allow_websocket_upgrade: host.allow_websocket_upgrade}, {enable_proxy_protocol: host.enable_proxy_protocol}, + {load_balancer_ip: host.load_balancer_ip}, {http2_support: host.http2_support}, {hsts_enabled: host.hsts_enabled}, {hsts_subdomains: host.hsts_subdomains}, {access_list: host.access_list}, {certificate: host.certificate}, host.locations[i]); diff --git a/backend/migrations/20220209144645_proxy_protocol.js b/backend/migrations/20220209144645_proxy_protocol.js new file mode 100644 index 00000000..8c809912 --- /dev/null +++ b/backend/migrations/20220209144645_proxy_protocol.js @@ -0,0 +1,36 @@ +const migrate_name = 'proxy_protocol'; +const logger = require('../logger').migrate; + +/** + * Migrate + * + * @see http://knexjs.org/#Schema + * + * @param {Object} knex + * @param {Promise} Promise + * @returns {Promise} + */ +exports.up = function (knex/*, Promise*/) { + logger.info('[' + migrate_name + '] Migrating Up...'); + + return knex.schema.table('proxy_host', function (proxy_host) { + proxy_host.integer('enable_proxy_protocol').notNull().unsigned().defaultTo(0); + proxy_host.string('load_balancer_ip').notNull().defaultTo(''); + }) + .then(() => { + logger.info('[' + migrate_name + '] proxy_host Table altered'); + }); + +}; + +/** + * Undo Migrate + * + * @param {Object} knex + * @param {Promise} Promise + * @returns {Promise} + */ +exports.down = function (knex, Promise) { + logger.warn('[' + migrate_name + '] You can\'t migrate down this one.'); + return Promise.resolve(true); +}; \ No newline at end of file diff --git a/backend/schema/endpoints/proxy-hosts.json b/backend/schema/endpoints/proxy-hosts.json index 9a3fff2f..27a8ec2a 100644 --- a/backend/schema/endpoints/proxy-hosts.json +++ b/backend/schema/endpoints/proxy-hosts.json @@ -58,6 +58,16 @@ "example": true, "type": "boolean" }, + "enable_proxy_protocol": { + "description": "Enable PROXY Protocol support", + "example": true, + "type": "boolean" + }, + "load_balancer_ip": { + "type": "string", + "minLength": 0, + "maxLength": 255 + }, "access_list_id": { "$ref": "../definitions.json#/definitions/access_list_id" }, @@ -155,6 +165,12 @@ "allow_websocket_upgrade": { "$ref": "#/definitions/allow_websocket_upgrade" }, + "enable_proxy_protocol": { + "$ref": "#/definitions/enable_proxy_protocol" + }, + "load_balancer_ip": { + "$ref": "#/definitions/load_balancer_ip" + }, "access_list_id": { "$ref": "#/definitions/access_list_id" }, @@ -245,6 +261,12 @@ "allow_websocket_upgrade": { "$ref": "#/definitions/allow_websocket_upgrade" }, + "enable_proxy_protocol": { + "$ref": "#/definitions/enable_proxy_protocol" + }, + "load_balancer_ip": { + "$ref": "#/definitions/load_balancer_ip" + }, "access_list_id": { "$ref": "#/definitions/access_list_id" }, @@ -318,6 +340,12 @@ "allow_websocket_upgrade": { "$ref": "#/definitions/allow_websocket_upgrade" }, + "enable_proxy_protocol": { + "$ref": "#/definitions/enable_proxy_protocol" + }, + "load_balancer_ip": { + "$ref": "#/definitions/load_balancer_ip" + }, "access_list_id": { "$ref": "#/definitions/access_list_id" }, diff --git a/backend/templates/_listen.conf b/backend/templates/_listen.conf index 730f3a7c..15f0c865 100644 --- a/backend/templates/_listen.conf +++ b/backend/templates/_listen.conf @@ -1,15 +1,25 @@ +{% if enable_proxy_protocol == 1 or enable_proxy_protocol == true%} + listen 88 proxy_protocol; +{% if ipv6 -%} + listen [::]:88 proxy_protocol; +{% endif %} +{% else -%} listen 80; {% if ipv6 -%} listen [::]:80; -{% else -%} - #listen [::]:80; +{% endif %} {% endif %} {% if certificate -%} +{% if enable_proxy_protocol == 1 or enable_proxy_protocol == true%} + listen 444 ssl{% if http2_support %} http2{% endif %} proxy_protocol; +{% if ipv6 -%} + listen [::]:444 ssl{% if http2_support %} http2{% endif %} proxy_protocol; +{% endif %} +{% else -%} listen 443 ssl{% if http2_support %} http2{% endif %}; {% if ipv6 -%} listen [::]:443 ssl{% if http2_support %} http2{% endif %}; -{% else -%} - #listen [::]:443; {% endif %} {% endif %} - server_name {{ domain_names | join: " " }}; +{% endif %} + server_name {{ domain_names | join: " " }}; \ No newline at end of file diff --git a/backend/templates/_proxy_protocol.conf b/backend/templates/_proxy_protocol.conf new file mode 100644 index 00000000..fa81494b --- /dev/null +++ b/backend/templates/_proxy_protocol.conf @@ -0,0 +1,6 @@ +{% if enable_proxy_protocol == 1 or enable_proxy_protocol == true %} +{% if load_balancer_ip != '' %} + set_real_ip_from {{ load_balancer_ip }}; + real_ip_header proxy_protocol; +{% endif %} +{% endif %} \ No newline at end of file diff --git a/backend/templates/proxy_host.conf b/backend/templates/proxy_host.conf index ec30cca0..d733c853 100644 --- a/backend/templates/proxy_host.conf +++ b/backend/templates/proxy_host.conf @@ -12,6 +12,7 @@ server { {% include "_exploits.conf" %} {% include "_hsts.conf" %} {% include "_forced_ssl.conf" %} +{% include "_proxy_protocol.conf" %} {% if allow_websocket_upgrade == 1 or allow_websocket_upgrade == true %} proxy_set_header Upgrade $http_upgrade; diff --git a/frontend/js/app/nginx/proxy/form.ejs b/frontend/js/app/nginx/proxy/form.ejs index 56868f55..9c30f13c 100644 --- a/frontend/js/app/nginx/proxy/form.ejs +++ b/frontend/js/app/nginx/proxy/form.ejs @@ -72,7 +72,7 @@ -
+
+
+
+ +
+
+
+
+ + > +
+
diff --git a/frontend/js/app/nginx/proxy/form.js b/frontend/js/app/nginx/proxy/form.js index 1dfb5c18..5ffd145a 100644 --- a/frontend/js/app/nginx/proxy/form.js +++ b/frontend/js/app/nginx/proxy/form.js @@ -43,7 +43,9 @@ module.exports = Mn.View.extend({ dns_provider_credentials: 'textarea[name="meta[dns_provider_credentials]"]', propagation_seconds: 'input[name="meta[propagation_seconds]"]', forward_scheme: 'select[name="forward_scheme"]', - letsencrypt: '.letsencrypt' + letsencrypt: '.letsencrypt', + enable_proxy_protocol: 'input[name="enable_proxy_protocol"]', + load_balancer_ip: 'input[name="load_balancer_ip"]' }, regions: { @@ -51,6 +53,14 @@ module.exports = Mn.View.extend({ }, events: { + 'change @ui.enable_proxy_protocol': function () { + let checked = this.ui.enable_proxy_protocol.prop('checked'); + this.ui.load_balancer_ip + .prop('disabled', !checked) + .parents('.form-group') + .css('opacity', checked ? 1 : 0.5); + }, + 'change @ui.certificate_select': function () { let id = this.ui.certificate_select.val(); if (id === 'new') { @@ -163,6 +173,7 @@ module.exports = Mn.View.extend({ data.block_exploits = !!data.block_exploits; data.caching_enabled = !!data.caching_enabled; data.allow_websocket_upgrade = !!data.allow_websocket_upgrade; + data.enable_proxy_protocol = !!data.enable_proxy_protocol; data.http2_support = !!data.http2_support; data.hsts_enabled = !!data.hsts_enabled; data.hsts_subdomains = !!data.hsts_subdomains; @@ -264,6 +275,7 @@ module.exports = Mn.View.extend({ onRender: function () { let view = this; + this.ui.enable_proxy_protocol.trigger('change'); this.ui.ssl_forced.trigger('change'); this.ui.hsts_enabled.trigger('change'); diff --git a/frontend/js/i18n/messages.json b/frontend/js/i18n/messages.json index 896a9633..1aaa3ac7 100644 --- a/frontend/js/i18n/messages.json +++ b/frontend/js/i18n/messages.json @@ -133,7 +133,9 @@ "allow-websocket-upgrade": "Websockets Support", "ignore-invalid-upstream-ssl": "Ignore Invalid SSL", "custom-forward-host-help": "Add a path for sub-folder forwarding.\nExample: 203.0.113.25/path", - "search": "Search Host…" + "search": "Search Host…", + "enable-proxy-protocol": "Enable PROXY Protocol", + "load-balancer-ip": "Load balancer or TCP proxy IP / CIDR range " }, "redirection-hosts": { "title": "Redirection Hosts", diff --git a/frontend/js/models/proxy-host.js b/frontend/js/models/proxy-host.js index b82d09fe..b1a80f54 100644 --- a/frontend/js/models/proxy-host.js +++ b/frontend/js/models/proxy-host.js @@ -19,6 +19,8 @@ const model = Backbone.Model.extend({ hsts_subdomains: false, caching_enabled: false, allow_websocket_upgrade: false, + enable_proxy_protocol: false, + load_balancer_ip: '', block_exploits: false, http2_support: false, advanced_config: '', From 5e733614da09af39479eb30a711da22d748ebc8a Mon Sep 17 00:00:00 2001 From: Austin Drummond Date: Mon, 28 Apr 2025 23:52:48 -0400 Subject: [PATCH 2/9] bump build --- backend/migrations/20220209144645_proxy_protocol.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/backend/migrations/20220209144645_proxy_protocol.js b/backend/migrations/20220209144645_proxy_protocol.js index 8c809912..f8a1710e 100644 --- a/backend/migrations/20220209144645_proxy_protocol.js +++ b/backend/migrations/20220209144645_proxy_protocol.js @@ -16,10 +16,9 @@ exports.up = function (knex/*, Promise*/) { return knex.schema.table('proxy_host', function (proxy_host) { proxy_host.integer('enable_proxy_protocol').notNull().unsigned().defaultTo(0); proxy_host.string('load_balancer_ip').notNull().defaultTo(''); - }) - .then(() => { - logger.info('[' + migrate_name + '] proxy_host Table altered'); - }); + }).then(() => { + logger.info('[' + migrate_name + '] proxy_host Table altered'); + }); }; @@ -33,4 +32,4 @@ exports.up = function (knex/*, Promise*/) { exports.down = function (knex, Promise) { logger.warn('[' + migrate_name + '] You can\'t migrate down this one.'); return Promise.resolve(true); -}; \ No newline at end of file +}; From cf4965c03e0146cfa26cc02c987046291ae9593f Mon Sep 17 00:00:00 2001 From: Vadim Isakov <43072246+Iaotle@users.noreply.github.com> Date: Tue, 1 Jul 2025 09:13:51 +0200 Subject: [PATCH 3/9] Update proxy_host.js --- backend/models/proxy_host.js | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/models/proxy_host.js b/backend/models/proxy_host.js index 07aa5dd3..87ce1782 100644 --- a/backend/models/proxy_host.js +++ b/backend/models/proxy_host.js @@ -21,6 +21,7 @@ const boolFields = [ 'enabled', 'hsts_enabled', 'hsts_subdomains', + 'enable_proxy_protocol' ]; class ProxyHost extends Model { From 1e080c2ac62cba0faa61e261a92ad3ff68043821 Mon Sep 17 00:00:00 2001 From: Austin Drummond Date: Fri, 25 Jul 2025 15:53:18 -0400 Subject: [PATCH 4/9] enable standard ports when proxy protocol is enabled --- backend/templates/_listen.conf | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/backend/templates/_listen.conf b/backend/templates/_listen.conf index 380f503f..d75bb34d 100644 --- a/backend/templates/_listen.conf +++ b/backend/templates/_listen.conf @@ -1,25 +1,29 @@ {% if enable_proxy_protocol == 1 or enable_proxy_protocol == true%} listen 88 proxy_protocol; + listen 80; {% if ipv6 -%} listen [::]:88 proxy_protocol; -{% endif %} + listen [::]:80; +{% endif %} {% else -%} listen 80; {% if ipv6 -%} listen [::]:80; -{% endif %} +{% endif %} {% endif %} {% if certificate -%} {% if enable_proxy_protocol == 1 or enable_proxy_protocol == true%} listen 444 ssl proxy_protocol; + listen 443 ssl; {% if ipv6 -%} listen [::]:444 ssl proxy_protocol; -{% endif %} + listen [::]:443 ssl; +{% endif %} {% else -%} listen 443 ssl; {% if ipv6 -%} listen [::]:443 ssl; -{% endif %} +{% endif %} {% endif %} {% else %} #listen [::]:443; From 5d14b744d6a83e474e909bb29cbc51c940aa162e Mon Sep 17 00:00:00 2001 From: Austin Drummond Date: Fri, 25 Jul 2025 15:56:50 -0400 Subject: [PATCH 5/9] always enable real ip proxy protocol if enabled --- backend/templates/_proxy_protocol.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/templates/_proxy_protocol.conf b/backend/templates/_proxy_protocol.conf index fa81494b..acba5e13 100644 --- a/backend/templates/_proxy_protocol.conf +++ b/backend/templates/_proxy_protocol.conf @@ -1,6 +1,6 @@ {% if enable_proxy_protocol == 1 or enable_proxy_protocol == true %} {% if load_balancer_ip != '' %} set_real_ip_from {{ load_balancer_ip }}; - real_ip_header proxy_protocol; {% endif %} -{% endif %} \ No newline at end of file +real_ip_header proxy_protocol; +{% endif %} From d55000a8c2e1f78084d04c5a64fe991cd8bde5e7 Mon Sep 17 00:00:00 2001 From: Austin Drummond Date: Sat, 23 May 2026 05:23:11 -0400 Subject: [PATCH 6/9] fix migration sequence and down --- .../20220209144645_proxy_protocol.js | 35 ---------------- .../20260425014441_proxy_protocol.js | 41 +++++++++++++++++++ 2 files changed, 41 insertions(+), 35 deletions(-) delete mode 100644 backend/migrations/20220209144645_proxy_protocol.js create mode 100644 backend/migrations/20260425014441_proxy_protocol.js diff --git a/backend/migrations/20220209144645_proxy_protocol.js b/backend/migrations/20220209144645_proxy_protocol.js deleted file mode 100644 index f8a1710e..00000000 --- a/backend/migrations/20220209144645_proxy_protocol.js +++ /dev/null @@ -1,35 +0,0 @@ -const migrate_name = 'proxy_protocol'; -const logger = require('../logger').migrate; - -/** - * Migrate - * - * @see http://knexjs.org/#Schema - * - * @param {Object} knex - * @param {Promise} Promise - * @returns {Promise} - */ -exports.up = function (knex/*, Promise*/) { - logger.info('[' + migrate_name + '] Migrating Up...'); - - return knex.schema.table('proxy_host', function (proxy_host) { - proxy_host.integer('enable_proxy_protocol').notNull().unsigned().defaultTo(0); - proxy_host.string('load_balancer_ip').notNull().defaultTo(''); - }).then(() => { - logger.info('[' + migrate_name + '] proxy_host Table altered'); - }); - -}; - -/** - * Undo Migrate - * - * @param {Object} knex - * @param {Promise} Promise - * @returns {Promise} - */ -exports.down = function (knex, Promise) { - logger.warn('[' + migrate_name + '] You can\'t migrate down this one.'); - return Promise.resolve(true); -}; diff --git a/backend/migrations/20260425014441_proxy_protocol.js b/backend/migrations/20260425014441_proxy_protocol.js new file mode 100644 index 00000000..e6d7e466 --- /dev/null +++ b/backend/migrations/20260425014441_proxy_protocol.js @@ -0,0 +1,41 @@ +const migrate_name = "proxy_protocol"; +import { migrate as logger } from "../logger.js"; + +/** + * Migrate + * + * @see http://knexjs.org/#Schema + * + * @param {Object} knex + * @returns {Promise} + */ +const up = (knex) => { + logger.info(`[${migrate_name}] Migrating Up...`); + + return knex.schema.table("proxy_host", (table) => { + table.integer("enable_proxy_protocol").notNull().unsigned().defaultTo(0); + table.string("load_balancer_ip").notNull().defaultTo(""); + }).then(() => { + logger.info(`[${migrate_name}] proxy_host Table altered`); + }); +}; + +/** + * Undo Migrate + * + * @param {Object} knex + * @returns {Promise} + */ +const down = (knex) => { + logger.info(`[${migrate_name}] Migrating Down...`); + + return knex.schema.table("proxy_host", (table) => { + table.dropColumn("enable_proxy_protocol"); + table.dropColumn("load_balancer_ip"); + }) + .then(() => { + logger.info(`[${migrate_name}] proxy_host Table altered`); + }); +}; + +export { up, down }; From c8403678fff50db04bbfa1a57627550c5eb7c78e Mon Sep 17 00:00:00 2001 From: Austin Drummond Date: Sat, 23 May 2026 05:41:40 -0400 Subject: [PATCH 7/9] make load balancer ip required --- frontend/src/locale/src/en.json | 3 +++ frontend/src/modals/ProxyHostModal.tsx | 19 +++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/frontend/src/locale/src/en.json b/frontend/src/locale/src/en.json index 09ce13f8..71e28e55 100644 --- a/frontend/src/locale/src/en.json +++ b/frontend/src/locale/src/en.json @@ -395,6 +395,9 @@ "error.invalid-email": { "defaultMessage": "Invalid email address" }, + "error.invalid-ip-or-cidr": { + "defaultMessage": "Must be a valid IPv4/IPv6 address or CIDR range" + }, "error.max-character-length": { "defaultMessage": "Maximum length is {max} character{max, plural, one {} other {s}}" }, diff --git a/frontend/src/modals/ProxyHostModal.tsx b/frontend/src/modals/ProxyHostModal.tsx index 683bbc42..3d16604e 100644 --- a/frontend/src/modals/ProxyHostModal.tsx +++ b/frontend/src/modals/ProxyHostModal.tsx @@ -17,11 +17,20 @@ import { SSLOptionsFields, } from "src/components"; import { useProxyHost, useSetProxyHost, useUser } from "src/hooks"; -import { T } from "src/locale"; +import { intl, T } from "src/locale"; import { MANAGE, PROXY_HOSTS } from "src/modules/Permissions"; import { validateNumber, validateString } from "src/modules/Validations"; import { showObjectSuccess } from "src/notifications"; +const IP_OR_CIDR_RE = + /^(?:(?:25[0-5]|2[0-4]\d|[01]?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d?\d)(?:\/(?:3[0-2]|[12]?\d))?$|^[0-9a-fA-F:]+(?:\/(?:12[0-8]|1[01]\d|\d?\d))?$/; + +// Only invoked when enableProxyProtocol is true (Field is conditionally rendered). +const validateLoadBalancerIp = (value: string): string | undefined => { + if (!value || !value.length) return intl.formatMessage({ id: "error.required" }); + if (!IP_OR_CIDR_RE.test(value)) return intl.formatMessage({ id: "error.invalid-ip-or-cidr" }); +}; + const showProxyHostModal = (id: number | "new") => { EasyModal.show(ProxyHostModal, { id }); }; @@ -357,7 +366,7 @@ const ProxyHostModal = EasyModal.create(({ id, visible, remove }: Props) => { {({ field: enableField }: any) => enableField.value ? ( - + {({ field, form }: any) => (
)}
From 97e56f32b482445f6106cbaea58f89a2e19bb2a2 Mon Sep 17 00:00:00 2001 From: Austin Drummond Date: Sat, 23 May 2026 05:41:54 -0400 Subject: [PATCH 8/9] set real ip if load balancer ip is set --- backend/templates/_proxy_protocol.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/templates/_proxy_protocol.conf b/backend/templates/_proxy_protocol.conf index acba5e13..cba0424f 100644 --- a/backend/templates/_proxy_protocol.conf +++ b/backend/templates/_proxy_protocol.conf @@ -1,6 +1,6 @@ {% if enable_proxy_protocol == 1 or enable_proxy_protocol == true %} {% if load_balancer_ip != '' %} set_real_ip_from {{ load_balancer_ip }}; + real_ip_header proxy_protocol; {% endif %} -real_ip_header proxy_protocol; {% endif %} From a92e4859836a127c5ec5aa5be47400110addd518 Mon Sep 17 00:00:00 2001 From: Austin Drummond Date: Sat, 23 May 2026 05:56:01 -0400 Subject: [PATCH 9/9] update docs for proxy protocol --- docs/src/advanced-config/index.md | 34 +++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/docs/src/advanced-config/index.md b/docs/src/advanced-config/index.md index 3ab04ce2..71c6bf97 100644 --- a/docs/src/advanced-config/index.md +++ b/docs/src/advanced-config/index.md @@ -237,6 +237,40 @@ Setting these environment variables will create the default user on startup, ski INITIAL_ADMIN_PASSWORD: mypassword1 ``` +## PROXY Protocol Support + +Proxy hosts can opt-in to the PROXY protocol so the client's real IP is preserved when +NPM sits behind an upstream load balancer (AWS NLB, HAProxy, another nginx, etc.) that +speaks PROXY protocol. See nginx's [`ngx_http_realip_module`](https://nginx.org/en/docs/http/ngx_http_realip_module.html) +for how `set_real_ip_from` and `real_ip_header proxy_protocol` interact. + +When enabled on a proxy host, NPM listens for PROXY protocol traffic on additional ports: + +| Port | Purpose | +|------|-------------------------------| +| 88 | HTTP with PROXY protocol | +| 444 | HTTPS (TLS) with PROXY protocol | + +These ports are **not** exposed by default. Publish them in your `docker-compose.yml` +so your upstream load balancer can reach them: + +```yml +services: + app: + image: 'jc21/nginx-proxy-manager:{{VERSION}}' + ports: + - '80:80' + - '443:443' + - '81:81' + - '88:88' # PROXY protocol (HTTP) + - '444:444' # PROXY protocol (HTTPS) + # ... +``` + +When editing a proxy host, enable **PROXY Protocol** and supply the **Load Balancer IP / CIDR** +of the upstream that will be sending PROXY protocol headers. This value becomes the +`set_real_ip_from` directive — without it, nginx will not trust the forwarded client IP. + ## Disable Nginx Resolver On startup, we generate a resolvers directive for Nginx unless this is defined: