Add support for PROXY protocol on streams

This commit is contained in:
Semjon Nordmann
2024-03-10 10:58:22 +01:00
parent 72abe50799
commit da29cd2e0e
8 changed files with 141 additions and 19 deletions

View File

@ -0,0 +1,41 @@
const migrate_name = 'proxy_protocol_streams';
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('stream', function (stream) {
stream.integer('enable_proxy_protocol').notNull().unsigned().defaultTo(0);
stream.string('load_balancer_ip').notNull().defaultTo('');
})
.then(() => {
logger.info('[' + migrate_name + '] stream Table altered');
});
};
/**
* Undo Migrate
*
* @param {Object} knex
* @param {Promise} Promise
* @returns {Promise}
*/
exports.down = function (knex/*, Promise*/) {
return knex.schema.table('stream', function (stream) {
stream.dropColumn('enable_proxy_protocol');
stream.dropColumn('load_balancer_ip');
})
.then(function () {
logger.info('[' + migrate_name + '] stream Table altered');
});
};

View File

@ -46,6 +46,16 @@
"udp_forwarding": { "udp_forwarding": {
"type": "boolean" "type": "boolean"
}, },
"enable_proxy_protocol": {
"description": "Enable PROXY Protocol support",
"example": true,
"type": "boolean"
},
"load_balancer_ip": {
"type": "string",
"minLength": 0,
"maxLength": 255
},
"enabled": { "enabled": {
"$ref": "../definitions.json#/definitions/enabled" "$ref": "../definitions.json#/definitions/enabled"
}, },
@ -78,6 +88,12 @@
"udp_forwarding": { "udp_forwarding": {
"$ref": "#/definitions/udp_forwarding" "$ref": "#/definitions/udp_forwarding"
}, },
"enable_proxy_protocol": {
"$ref": "#/definitions/enable_proxy_protocol"
},
"load_balancer_ip": {
"$ref": "#/definitions/load_balancer_ip"
},
"enabled": { "enabled": {
"$ref": "#/definitions/enabled" "$ref": "#/definitions/enabled"
}, },
@ -137,6 +153,12 @@
"udp_forwarding": { "udp_forwarding": {
"$ref": "#/definitions/udp_forwarding" "$ref": "#/definitions/udp_forwarding"
}, },
"enable_proxy_protocol": {
"$ref": "#/definitions/enable_proxy_protocol"
},
"load_balancer_ip": {
"$ref": "#/definitions/load_balancer_ip"
},
"meta": { "meta": {
"$ref": "#/definitions/meta" "$ref": "#/definitions/meta"
} }
@ -177,6 +199,12 @@
"udp_forwarding": { "udp_forwarding": {
"$ref": "#/definitions/udp_forwarding" "$ref": "#/definitions/udp_forwarding"
}, },
"enable_proxy_protocol": {
"$ref": "#/definitions/enable_proxy_protocol"
},
"load_balancer_ip": {
"$ref": "#/definitions/load_balancer_ip"
},
"meta": { "meta": {
"$ref": "#/definitions/meta" "$ref": "#/definitions/meta"
} }

View File

@ -1,31 +1,38 @@
# ------------------------------------------------------------ # ------------------------------------------------------------
# {{ incoming_port }} TCP: {{ tcp_forwarding }} UDP: {{ udp_forwarding }} # {{ incoming_port }} TCP: {{ tcp_forwarding }} UDP: {{ udp_forwarding }}
# ------------------------------------------------------------ # ------------------------------------------------------------
{% if enable_proxy_protocol == 1 or enable_proxy_protocol == true -%}
{% capture listen_extra_args %}proxy_protocol{% endcapture -%}
{% endif -%}
{% if enabled %} {% if enabled %}
{% if tcp_forwarding == 1 or tcp_forwarding == true -%} {% if tcp_forwarding == 1 or tcp_forwarding == true -%}
server { server {
listen {{ incoming_port }}; listen {{ incoming_port }} {{ listen_extra_args }};
{% if ipv6 -%} {% if ipv6 -%}
listen [::]:{{ incoming_port }}; listen [::]:{{ incoming_port }} {{ listen_extra_args }};
{% else -%} {% else -%}
#listen [::]:{{ incoming_port }}; #listen [::]:{{ incoming_port }} {{ listen_extra_args }};
{% endif %} {% endif %}
proxy_pass {{ forwarding_host }}:{{ forwarding_port }}; proxy_pass {{ forwarding_host }}:{{ forwarding_port }};
{% include '_proxy_protocol.conf' %}
# Custom # Custom
include /data/nginx/custom/server_stream[.]conf; include /data/nginx/custom/server_stream[.]conf;
include /data/nginx/custom/server_stream_tcp[.]conf; include /data/nginx/custom/server_stream_tcp[.]conf;
} }
{% endif %} {% endif %}
{% if udp_forwarding == 1 or udp_forwarding == true %} {% if udp_forwarding == 1 or udp_forwarding == true %}
{% # Proxy Protocol is not supported for UDP %}
{% assign listen_extra_args = "" %}
server { server {
listen {{ incoming_port }} udp; listen {{ incoming_port }} udp {{ listen_extra_args }};
{% if ipv6 -%} {% if ipv6 -%}
listen [::]:{{ incoming_port }} udp; listen [::]:{{ incoming_port }} udp {{ listen_extra_args }};
{% else -%} {% else -%}
#listen [::]:{{ incoming_port }} udp; #listen [::]:{{ incoming_port }} udp {{ listen_extra_args }};
{% endif %} {% endif %}
proxy_pass {{ forwarding_host }}:{{ forwarding_port }}; proxy_pass {{ forwarding_host }}:{{ forwarding_port }};

View File

@ -209,14 +209,26 @@ You can customise the logrotate configuration through a mount (if your custom co
For reference, the default configuration can be found [here](https://github.com/NginxProxyManager/nginx-proxy-manager/blob/develop/docker/rootfs/etc/logrotate.d/nginx-proxy-manager). For reference, the default configuration can be found [here](https://github.com/NginxProxyManager/nginx-proxy-manager/blob/develop/docker/rootfs/etc/logrotate.d/nginx-proxy-manager).
## Enabling Proxy Protocol for Proxy Hosts ## Enabling PROXY protocol for Proxy Hosts
When running NPM behind a load balancer, you might want to use the [PROXY procotol](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt) to receive client information such as the source IP address (useful for banning IPs). When running NPM behind a load balancer, you might want to use the [PROXY procotol](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt) to receive client information such as the source IP address (useful for banning IPs).
When configuring the PROXY protocol for proxy hosts, NPM uses the ports 88 for http and 444 for https traffic to allow you to decide on a per host basis whether to use the PROSY protocol. When configuring the PROXY protocol for proxy hosts, NPM uses the ports 88 for http and 444 for https traffic to allow you to decide on a per host basis whether to use the PROSY protocol.
To enable the Proxy Protocol for your hosts you need to perform the following steps: To enable the PROXY protocol for your hosts you need to perform the following steps:
1. Expose the ports `88` (and `444` is applicable) by adjusting your `docker-compose.yml` 1. Expose the ports `88` (and `444` is applicable) by adjusting your `docker-compose.yml`
2. Edit your proxy hosts to enable the PROXY protocol 2. Edit your proxy hosts to enable the PROXY protocol
3. Edit your upstream load balancer to redirect traffic to the port `88`/`444` and enable the PROXY protocol 3. Edit your upstream load balancer to redirect traffic to the port `88`/`444` and enable the PROXY protocol
## Enabling PROXY protocol for Streams
When running NPM behind a load balancer, you might want to use the [PROXY procotol](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt) to receive client information such as the source IP address (useful for banning IPs).
Keep in mind that the PROXY procotol cannot be enabled for udp endpoints.
To enable the PROXY protocol for streams:
1. Expose the desired port by adjusting you `docker-compose.yml`
2. Edit the Stream to enable the PROXY protocol
3. Edit your upstream load balancer to enable the PROXY protocol

View File

@ -42,6 +42,22 @@
</label> </label>
</div> </div>
</div> </div>
<div class="col-sm-6 col-md-6">
<div class="form-group">
<label class="custom-switch">
<input type="checkbox" class="custom-switch-input" name="enable_proxy_protocol" value="1"<%- enable_proxy_protocol ? ' checked' : '' %>>
<span class="custom-switch-indicator"></span>
<span class="custom-switch-description"><%- i18n('streams', 'enable-proxy-protocol') %><a href="https://docs.nginx.com/nginx/admin-guide/load-balancer/using-proxy-protocol/#introduction" target="_blank"><i class="fe fe-help-circle"></i></a></span>
</label>
</div>
</div>
<div class="col-sm-12 col-md-12">
<div class="form-group">
<label class="form-label"><%- i18n('streams', 'load-balancer-ip') %><a href="https://docs.nginx.com/nginx/admin-guide/load-balancer/using-proxy-protocol/#changing-the-load-balancers-ip-address-to-the-client-ip-address" target="_blank"><i class="fe fe-help-circle"></i></a></label>
<input type="text" name="load_balancer_ip" class="form-control text-monospace" placeholder="" value="<%- load_balancer_ip %>" autocomplete="off" maxlength="255" <%- enable_proxy_protocol ? '' : ' disabled' %>>
</div>
</div>
<div class="col-sm-12 col-md-12"> <div class="col-sm-12 col-md-12">
<div class="forward-type-error invalid-feedback"><%- i18n('streams', 'forward-type-error') %></div> <div class="forward-type-error invalid-feedback"><%- i18n('streams', 'forward-type-error') %></div>
</div> </div>

View File

@ -14,6 +14,8 @@ module.exports = Mn.View.extend({
ui: { ui: {
form: 'form', form: 'form',
forwarding_host: 'input[name="forwarding_host"]', forwarding_host: 'input[name="forwarding_host"]',
enable_proxy_protocol: 'input[name="enable_proxy_protocol"]',
load_balancer_ip: 'input[name="load_balancer_ip"]',
type_error: '.forward-type-error', type_error: '.forward-type-error',
buttons: '.modal-footer button', buttons: '.modal-footer button',
switches: '.custom-switch-input', switches: '.custom-switch-input',
@ -22,6 +24,13 @@ module.exports = Mn.View.extend({
}, },
events: { 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.switches': function () { 'change @ui.switches': function () {
this.ui.type_error.hide(); this.ui.type_error.hide();
}, },
@ -47,6 +56,7 @@ module.exports = Mn.View.extend({
data.forwarding_port = parseInt(data.forwarding_port, 10); data.forwarding_port = parseInt(data.forwarding_port, 10);
data.tcp_forwarding = !!data.tcp_forwarding; data.tcp_forwarding = !!data.tcp_forwarding;
data.udp_forwarding = !!data.udp_forwarding; data.udp_forwarding = !!data.udp_forwarding;
data.enable_proxy_protocol = !!data.enable_proxy_protocol;
let method = App.Api.Nginx.Streams.create; let method = App.Api.Nginx.Streams.create;
let is_new = true; let is_new = true;
@ -76,6 +86,10 @@ module.exports = Mn.View.extend({
} }
}, },
onRender: function () {
this.ui.enable_proxy_protocol.trigger('change');
},
initialize: function (options) { initialize: function (options) {
if (typeof options.model === 'undefined' || !options.model) { if (typeof options.model === 'undefined' || !options.model) {
this.model = new StreamModel.Model(); this.model = new StreamModel.Model();

View File

@ -177,6 +177,8 @@
"protocol": "Protocol", "protocol": "Protocol",
"tcp": "TCP", "tcp": "TCP",
"udp": "UDP", "udp": "UDP",
"enable-proxy-protocol": "Enable Proxy Protocol",
"load-balancer-ip": "Load balancer or TCP proxy IP / CIDR range",
"delete": "Delete Stream", "delete": "Delete Stream",
"delete-confirm": "Are you sure you want to delete this Stream?", "delete-confirm": "Are you sure you want to delete this Stream?",
"help-title": "What is a Stream?", "help-title": "What is a Stream?",

View File

@ -13,6 +13,8 @@ const model = Backbone.Model.extend({
forwarding_port: null, forwarding_port: null,
tcp_forwarding: true, tcp_forwarding: true,
udp_forwarding: false, udp_forwarding: false,
enable_proxy_protocol: false,
load_balancer_ip: "",
enabled: true, enabled: true,
meta: {}, meta: {},
// The following are expansions: // The following are expansions: