Skip to content

Commit

Permalink
Add support for proxy_protocol in proxy_hosts and streams
Browse files Browse the repository at this point in the history
Closes NginxProxyManager#1114
Related To NginxProxyManager#1882
Related To NginxProxyManager#3537
Related To NginxProxyManager#3618

Co-authored-by: jwklijnsma <[email protected]>
Co-authored-by: SBado <[email protected]>
  • Loading branch information
3 people committed Oct 23, 2024
1 parent ee41bb5 commit fc6a313
Show file tree
Hide file tree
Showing 30 changed files with 271 additions and 28 deletions.
3 changes: 2 additions & 1 deletion backend/internal/nginx.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,8 @@ const internalNginx = {
{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},
{hsts_enabled: host.hsts_enabled}, {hsts_subdomains: host.hsts_subdomains}, {access_list: host.access_list},
{certificate: host.certificate}, host.locations[i]);
{certificate: host.certificate}, {proxy_protocol_enabled: host.proxy_protocol_enabled},
{loadbalancer_address: host.loadbalancer_address}, host.locations[i]);

if (locationCopy.forward_host.indexOf('/') > -1) {
const splitted = locationCopy.forward_host.split('/');
Expand Down
56 changes: 56 additions & 0 deletions backend/migrations/20241022221324_proxy_protocol.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
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('proxy_protocol_enabled').notNull().defaultTo(0);
proxy_host.string('loadbalancer_address').notNull().defaultTo('');
})
.then(() => {
logger.info('[' + migrate_name + '] proxy_host Table altered');

return knex.schema.table('stream', function (stream) {
stream.integer('proxy_protocol_enabled').notNull().defaultTo(0);
stream.string('loadbalancer_address').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('proxy_host', function (proxy_host) {
proxy_host.dropColumn('proxy_protocol_enabled');
proxy_host.dropColumn('loadbalancer_address');
})
.then(function () {
logger.info('[' + migrate_name + '] proxy_host Table altered');
return knex.schema.table('stream', function (stream) {
stream.dropColumn('proxy_protocol_enabled');
stream.dropColumn('loadbalancer_address');
})
.then(function () {
logger.info('[' + migrate_name + '] stream Table altered');
});
});
};
1 change: 1 addition & 0 deletions backend/models/proxy_host.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const boolFields = [
'enabled',
'hsts_enabled',
'hsts_subdomains',
'proxy_protocol_enabled',
];

class ProxyHost extends Model {
Expand Down
1 change: 1 addition & 0 deletions backend/models/stream.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const boolFields = [
'is_deleted',
'tcp_forwarding',
'udp_forwarding',
'proxy_protocol_enabled',
];

class Stream extends Model {
Expand Down
10 changes: 10 additions & 0 deletions backend/schema/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,16 @@
"caching_enabled": {
"description": "Should we cache assets",
"type": "boolean"
},
"proxy_protocol_enabled": {
"description": "Should the proxy_procotol be enabled",
"type": "boolean"
},
"loadbalancer_address": {
"description": "Hostname, IP or CIDR range of the load balancer",
"type": "string",
"minLength": 0,
"maxLength": 255
}
}
}
10 changes: 9 additions & 1 deletion backend/schema/components/proxy-host-object.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
"locations",
"hsts_enabled",
"hsts_subdomains",
"certificate"
"certificate",
"proxy_protocol_enabled",
"loadbalancer_address"
],
"additionalProperties": false,
"properties": {
Expand Down Expand Up @@ -137,6 +139,12 @@
}
]
},
"proxy_protocol_enabled": {
"$ref": "../common.json#/properties/proxy_protocol_enabled"
},
"loadbalancer_address": {
"$ref": "../common.json#/properties/loadbalancer_address"
},
"owner": {
"$ref": "./user-object.json"
},
Expand Down
8 changes: 7 additions & 1 deletion backend/schema/components/stream-object.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"type": "object",
"description": "Stream object",
"required": ["id", "created_on", "modified_on", "owner_user_id", "incoming_port", "forwarding_host", "forwarding_port", "tcp_forwarding", "udp_forwarding", "enabled", "meta"],
"required": ["id", "created_on", "modified_on", "owner_user_id", "incoming_port", "forwarding_host", "forwarding_port", "tcp_forwarding", "udp_forwarding", "enabled", "meta", "proxy_protocol_enabled", "loadbalancer_address"],
"additionalProperties": false,
"properties": {
"id": {
Expand Down Expand Up @@ -55,6 +55,12 @@
},
"meta": {
"type": "object"
},
"proxy_protocol_enabled": {
"$ref": "../common.json#/properties/proxy_protocol_enabled"
},
"loadbalancer_address": {
"$ref": "../common.json#/properties/loadbalancer_address"
}
}
}
4 changes: 3 additions & 1 deletion backend/schema/paths/nginx/proxy-hosts/get.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@
"enabled": true,
"locations": null,
"hsts_enabled": false,
"hsts_subdomains": false
"hsts_subdomains": false,
"proxy_protocol_enabled": false,
"loadbalancer_address": ""
}
]
}
Expand Down
4 changes: 3 additions & 1 deletion backend/schema/paths/nginx/proxy-hosts/hostID/get.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@
"enabled": true,
"locations": null,
"hsts_enabled": false,
"hsts_subdomains": false
"hsts_subdomains": false,
"proxy_protocol_enabled": false,
"loadbalancer_address": ""
}
}
},
Expand Down
8 changes: 8 additions & 0 deletions backend/schema/paths/nginx/proxy-hosts/hostID/put.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@
},
"locations": {
"$ref": "../../../../components/proxy-host-object.json#/properties/locations"
},
"proxy_protocol_enabled": {
"$ref": "../../../../components/proxy-host-object.json#/properties/proxy_protocol_enabled"
},
"loadbalancer_address": {
"$ref": "../../../../components/proxy-host-object.json#/properties/loadbalancer_address"
}
}
}
Expand Down Expand Up @@ -116,6 +122,8 @@
"enabled": true,
"hsts_enabled": false,
"hsts_subdomains": false,
"proxy_protocol_enabled": false,
"loadbalancer_address": "",
"owner": {
"id": 1,
"created_on": "2024-10-07T22:43:55.000Z",
Expand Down
8 changes: 8 additions & 0 deletions backend/schema/paths/nginx/proxy-hosts/post.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@
},
"locations": {
"$ref": "../../../components/proxy-host-object.json#/properties/locations"
},
"proxy_protocol_enabled": {
"$ref": "../../../components/proxy-host-object.json#/properties/proxy_protocol_enabled"
},
"loadbalancer_address": {
"$ref": "../../../components/proxy-host-object.json#/properties/loadbalancer_address"
}
}
}
Expand Down Expand Up @@ -101,6 +107,8 @@
"enabled": true,
"hsts_enabled": false,
"hsts_subdomains": false,
"proxy_protocol_enabled": false,
"loadbalancer_address": "",
"certificate": null,
"owner": {
"id": 1,
Expand Down
2 changes: 2 additions & 0 deletions backend/schema/paths/nginx/streams/get.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
"forwarding_port": 80,
"tcp_forwarding": true,
"udp_forwarding": false,
"proxy_protocol_enabled": false,
"loadbalancer_address": "",
"meta": {
"nginx_online": true,
"nginx_err": null
Expand Down
8 changes: 8 additions & 0 deletions backend/schema/paths/nginx/streams/post.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@
"udp_forwarding": {
"$ref": "../../../components/stream-object.json#/properties/udp_forwarding"
},
"proxy_protocol_enabled": {
"$ref": "../../../components/stream-object.json#/properties/proxy_protocol_enabled"
},
"loadbalancer_address": {
"$ref": "../../../components/stream-object.json#/properties/loadbalancer_address"
},
"meta": {
"$ref": "../../../components/stream-object.json#/properties/meta"
}
Expand All @@ -57,6 +63,8 @@
"forwarding_port": 80,
"tcp_forwarding": true,
"udp_forwarding": false,
"proxy_protocol_enabled": false,
"loadbalancer_address": "",
"meta": {
"nginx_online": true,
"nginx_err": null
Expand Down
34 changes: 24 additions & 10 deletions backend/templates/_listen.conf
Original file line number Diff line number Diff line change
@@ -1,15 +1,29 @@
listen 80;

{% if proxy_protocol_enabled == 1 or proxy_protocol_enabled == true -%}
{% assign port_number_http = "88" -%}
{% assign port_number_https = "444" -%}
{% assign listen_extra_args = "proxy_protocol" -%}
{% else -%}
{% assign port_number_http = "80" -%}
{% assign port_number_https = "443" -%}
{% assign listen_extra_args = "" -%}
{% endif -%}

listen {{ port_number_http }} {{ listen_extra_args }};
{% if ipv6 -%}
listen [::]:80;
listen [::]:{{ port_number_http }} {{ listen_extra_args }};
{% else -%}
#listen [::]:80;
{% endif %}
#listen [::]:{{ port_number_http }} {{ listen_extra_args }};
{% endif -%}

{% if certificate -%}
listen 443 ssl{% if http2_support == 1 or http2_support == true %} http2{% endif %};
{% capture listen_extra_args_https %}ssl{% if http2_support %} http2{% endif %} {{ listen_extra_args }}{% endcapture -%}
listen {{ port_number_https }} {{ listen_extra_args_https }};
{% if ipv6 -%}
listen [::]:443 ssl{% if http2_support == 1 or http2_support == true %} http2{% endif %};
listen [::]:{{ port_number_https }} {{ listen_extra_args_https }};
{% else -%}
#listen [::]:443;
{% endif %}
{% endif %}
server_name {{ domain_names | join: " " }};
#listen [::]:{{ port_number_https }} {{ listen_extra_args_https }};
{% endif -%}
{% endif -%}

server_name {{ domain_names | join: " " }};
6 changes: 6 additions & 0 deletions backend/templates/_proxy_protocol.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{% if proxy_protocol_enabled == 1 or proxy_protocol_enabled == true %}
{% if loadbalancer_address != '' %}
set_real_ip_from {{ loadbalancer_address }};
real_ip_header proxy_protocol;
{% endif %}
{% endif %}
1 change: 1 addition & 0 deletions backend/templates/proxy_host.conf
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,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;
Expand Down
19 changes: 13 additions & 6 deletions backend/templates/stream.conf
Original file line number Diff line number Diff line change
@@ -1,31 +1,38 @@
# ------------------------------------------------------------
# {{ incoming_port }} TCP: {{ tcp_forwarding }} UDP: {{ udp_forwarding }}
# ------------------------------------------------------------
{% if proxy_protocol_enabled == 1 or proxy_protocol_enabled == true -%}
{% capture listen_extra_args %}proxy_protocol{% endcapture -%}
{% endif -%}

{% if enabled %}
{% if tcp_forwarding == 1 or tcp_forwarding == true -%}
server {
listen {{ incoming_port }};
listen {{ incoming_port }} {{ listen_extra_args }};
{% if ipv6 -%}
listen [::]:{{ incoming_port }};
listen [::]:{{ incoming_port }} {{ listen_extra_args }};
{% else -%}
#listen [::]:{{ incoming_port }};
#listen [::]:{{ incoming_port }}{{ listen_extra_args }};
{% endif %}

proxy_pass {{ forwarding_host }}:{{ forwarding_port }};

{% include '_proxy_protocol.conf' %}

# Custom
include /data/nginx/custom/server_stream[.]conf;
include /data/nginx/custom/server_stream_tcp[.]conf;
}
{% endif %}
{% if udp_forwarding == 1 or udp_forwarding == true %}
{% # Proxy Protocol is not supported for UDP %}
{% assign listen_extra_args = "" %}
server {
listen {{ incoming_port }} udp;
listen {{ incoming_port }} udp {{ listen_extra_args }};
{% if ipv6 -%}
listen [::]:{{ incoming_port }} udp;
listen [::]:{{ incoming_port }} udp {{ listen_extra_args }};
{% else -%}
#listen [::]:{{ incoming_port }} udp;
#listen [::]:{{ incoming_port }} udp {{ listen_extra_args }};
{% endif %}
proxy_pass {{ forwarding_host }}:{{ forwarding_port }};

Expand Down
3 changes: 2 additions & 1 deletion docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ RUN echo "fs.file-max = 65535" > /etc/sysctl.conf \
COPY docker/scripts/install-s6 /tmp/install-s6
RUN /tmp/install-s6 "${TARGETPLATFORM}" && rm -f /tmp/install-s6

EXPOSE 80 81 443
# http admin_ui http_proxy_protocol https https_proxy_protocol
EXPOSE 80 81 88 443 444

COPY backend /app
COPY frontend/dist /app/frontend
Expand Down
3 changes: 2 additions & 1 deletion docker/dev/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,6 @@ RUN rm -f /etc/nginx/conf.d/production.conf \
COPY --from=pebbleca /test/certs/pebble.minica.pem /etc/ssl/certs/pebble.minica.pem
COPY --from=testca /home/step/certs/root_ca.crt /etc/ssl/certs/NginxProxyManager.crt

EXPOSE 80 81 443
# http admin_ui http_proxy_protocol https https_proxy_protocol
EXPOSE 80 81 88 443 444
ENTRYPOINT [ "/init" ]
2 changes: 2 additions & 0 deletions docker/docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ services:
ports:
- 3080:80
- 3081:81
- 3088:88
- 3443:443
- 3444:444
networks:
nginx_proxy_manager:
aliases:
Expand Down
Loading

0 comments on commit fc6a313

Please sign in to comment.