Skip to content

Commit 480c772

Browse files
snordmannjwklijnsmaSBado
committed
Add support for proxy_protocol in proxy_hosts and streams
Closes #1114 Related To #1882 Related To #3537 Related To #3618 Co-authored-by: jwklijnsma <[email protected]> Co-authored-by: SBado <[email protected]>
1 parent eaf6335 commit 480c772

32 files changed

+281
-28
lines changed

backend/internal/nginx.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,8 @@ const internalNginx = {
156156
{ssl_forced: host.ssl_forced}, {caching_enabled: host.caching_enabled}, {block_exploits: host.block_exploits},
157157
{allow_websocket_upgrade: host.allow_websocket_upgrade}, {http2_support: host.http2_support},
158158
{hsts_enabled: host.hsts_enabled}, {hsts_subdomains: host.hsts_subdomains}, {access_list: host.access_list},
159-
{certificate: host.certificate}, host.locations[i]);
159+
{certificate: host.certificate}, {proxy_protocol_enabled: host.proxy_protocol_enabled},
160+
{loadbalancer_address: host.loadbalancer_address}, host.locations[i]);
160161

161162
if (locationCopy.forward_host.indexOf('/') > -1) {
162163
const splitted = locationCopy.forward_host.split('/');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
const migrate_name = 'proxy_protocol';
2+
const logger = require('../logger').migrate;
3+
4+
/**
5+
* Migrate
6+
*
7+
* @see http://knexjs.org/#Schema
8+
*
9+
* @param {Object} knex
10+
* @param {Promise} Promise
11+
* @returns {Promise}
12+
*/
13+
exports.up = function (knex/*, Promise*/) {
14+
logger.info('[' + migrate_name + '] Migrating Up...');
15+
16+
return knex.schema.table('proxy_host', function (proxy_host) {
17+
proxy_host.integer('proxy_protocol_enabled').notNull().defaultTo(0);
18+
proxy_host.string('loadbalancer_address').notNull().defaultTo('');
19+
})
20+
.then(() => {
21+
logger.info('[' + migrate_name + '] proxy_host Table altered');
22+
23+
return knex.schema.table('stream', function (stream) {
24+
stream.integer('proxy_protocol_enabled').notNull().defaultTo(0);
25+
stream.string('loadbalancer_address').notNull().defaultTo('');
26+
})
27+
.then(() => {
28+
logger.info('[' + migrate_name + '] stream Table altered');
29+
});
30+
});
31+
32+
};
33+
34+
/**
35+
* Undo Migrate
36+
*
37+
* @param {Object} knex
38+
* @param {Promise} Promise
39+
* @returns {Promise}
40+
*/
41+
exports.down = function (knex/*, Promise*/) {
42+
return knex.schema.table('proxy_host', function (proxy_host) {
43+
proxy_host.dropColumn('proxy_protocol_enabled');
44+
proxy_host.dropColumn('loadbalancer_address');
45+
})
46+
.then(function () {
47+
logger.info('[' + migrate_name + '] proxy_host Table altered');
48+
return knex.schema.table('stream', function (stream) {
49+
stream.dropColumn('proxy_protocol_enabled');
50+
stream.dropColumn('loadbalancer_address');
51+
})
52+
.then(function () {
53+
logger.info('[' + migrate_name + '] stream Table altered');
54+
});
55+
});
56+
};

backend/models/proxy_host.js

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ const boolFields = [
2121
'enabled',
2222
'hsts_enabled',
2323
'hsts_subdomains',
24+
'proxy_protocol_enabled',
2425
];
2526

2627
class ProxyHost extends Model {

backend/models/stream.js

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const boolFields = [
1313
'is_deleted',
1414
'tcp_forwarding',
1515
'udp_forwarding',
16+
'proxy_protocol_enabled',
1617
];
1718

1819
class Stream extends Model {

backend/schema/common.json

+10
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,16 @@
110110
"caching_enabled": {
111111
"description": "Should we cache assets",
112112
"type": "boolean"
113+
},
114+
"proxy_protocol_enabled": {
115+
"description": "Should the proxy_procotol be enabled",
116+
"type": "boolean"
117+
},
118+
"loadbalancer_address": {
119+
"description": "Hostname, IP or CIDR range of the load balancer",
120+
"type": "string",
121+
"minLength": 0,
122+
"maxLength": 255
113123
}
114124
}
115125
}

backend/schema/components/proxy-host-object.json

+9-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
"locations",
2424
"hsts_enabled",
2525
"hsts_subdomains",
26-
"certificate"
26+
"certificate",
27+
"proxy_protocol_enabled",
28+
"loadbalancer_address"
2729
],
2830
"additionalProperties": false,
2931
"properties": {
@@ -137,6 +139,12 @@
137139
}
138140
]
139141
},
142+
"proxy_protocol_enabled": {
143+
"$ref": "../common.json#/properties/proxy_protocol_enabled"
144+
},
145+
"loadbalancer_address": {
146+
"$ref": "../common.json#/properties/loadbalancer_address"
147+
},
140148
"owner": {
141149
"$ref": "./user-object.json"
142150
},

backend/schema/components/stream-object.json

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"type": "object",
33
"description": "Stream object",
4-
"required": ["id", "created_on", "modified_on", "owner_user_id", "incoming_port", "forwarding_host", "forwarding_port", "tcp_forwarding", "udp_forwarding", "enabled", "meta"],
4+
"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"],
55
"additionalProperties": false,
66
"properties": {
77
"id": {
@@ -55,6 +55,12 @@
5555
},
5656
"meta": {
5757
"type": "object"
58+
},
59+
"proxy_protocol_enabled": {
60+
"$ref": "../common.json#/properties/proxy_protocol_enabled"
61+
},
62+
"loadbalancer_address": {
63+
"$ref": "../common.json#/properties/loadbalancer_address"
5864
}
5965
}
6066
}

backend/schema/paths/nginx/proxy-hosts/get.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@
5050
"enabled": true,
5151
"locations": null,
5252
"hsts_enabled": false,
53-
"hsts_subdomains": false
53+
"hsts_subdomains": false,
54+
"proxy_protocol_enabled": false,
55+
"loadbalancer_address": ""
5456
}
5557
]
5658
}

backend/schema/paths/nginx/proxy-hosts/hostID/get.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@
5050
"enabled": true,
5151
"locations": null,
5252
"hsts_enabled": false,
53-
"hsts_subdomains": false
53+
"hsts_subdomains": false,
54+
"proxy_protocol_enabled": false,
55+
"loadbalancer_address": ""
5456
}
5557
}
5658
},

backend/schema/paths/nginx/proxy-hosts/hostID/put.json

+8
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@
7979
},
8080
"locations": {
8181
"$ref": "../../../../components/proxy-host-object.json#/properties/locations"
82+
},
83+
"proxy_protocol_enabled": {
84+
"$ref": "../../../../components/proxy-host-object.json#/properties/proxy_protocol_enabled"
85+
},
86+
"loadbalancer_address": {
87+
"$ref": "../../../../components/proxy-host-object.json#/properties/loadbalancer_address"
8288
}
8389
}
8490
}
@@ -116,6 +122,8 @@
116122
"enabled": true,
117123
"hsts_enabled": false,
118124
"hsts_subdomains": false,
125+
"proxy_protocol_enabled": false,
126+
"loadbalancer_address": "",
119127
"owner": {
120128
"id": 1,
121129
"created_on": "2024-10-07T22:43:55.000Z",

backend/schema/paths/nginx/proxy-hosts/post.json

+8
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@
6767
},
6868
"locations": {
6969
"$ref": "../../../components/proxy-host-object.json#/properties/locations"
70+
},
71+
"proxy_protocol_enabled": {
72+
"$ref": "../../../components/proxy-host-object.json#/properties/proxy_protocol_enabled"
73+
},
74+
"loadbalancer_address": {
75+
"$ref": "../../../components/proxy-host-object.json#/properties/loadbalancer_address"
7076
}
7177
}
7278
}
@@ -101,6 +107,8 @@
101107
"enabled": true,
102108
"hsts_enabled": false,
103109
"hsts_subdomains": false,
110+
"proxy_protocol_enabled": false,
111+
"loadbalancer_address": "",
104112
"certificate": null,
105113
"owner": {
106114
"id": 1,

backend/schema/paths/nginx/streams/get.json

+2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
"forwarding_port": 80,
3737
"tcp_forwarding": true,
3838
"udp_forwarding": false,
39+
"proxy_protocol_enabled": false,
40+
"loadbalancer_address": "",
3941
"meta": {
4042
"nginx_online": true,
4143
"nginx_err": null

backend/schema/paths/nginx/streams/post.json

+8
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@
3232
"udp_forwarding": {
3333
"$ref": "../../../components/stream-object.json#/properties/udp_forwarding"
3434
},
35+
"proxy_protocol_enabled": {
36+
"$ref": "../../../components/stream-object.json#/properties/proxy_protocol_enabled"
37+
},
38+
"loadbalancer_address": {
39+
"$ref": "../../../components/stream-object.json#/properties/loadbalancer_address"
40+
},
3541
"meta": {
3642
"$ref": "../../../components/stream-object.json#/properties/meta"
3743
}
@@ -57,6 +63,8 @@
5763
"forwarding_port": 80,
5864
"tcp_forwarding": true,
5965
"udp_forwarding": false,
66+
"proxy_protocol_enabled": false,
67+
"loadbalancer_address": "",
6068
"meta": {
6169
"nginx_online": true,
6270
"nginx_err": null

backend/schema/paths/nginx/streams/streamID/get.json

+2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
"forwarding_port": 80,
3737
"tcp_forwarding": true,
3838
"udp_forwarding": false,
39+
"proxy_protocol_enabled": false,
40+
"loadbalancer_address": "",
3941
"meta": {
4042
"nginx_online": true,
4143
"nginx_err": null

backend/schema/paths/nginx/streams/streamID/put.json

+8
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@
7979
},
8080
"locations": {
8181
"$ref": "../../../../components/proxy-host-object.json#/properties/locations"
82+
},
83+
"proxy_protocol_enabled": {
84+
"$ref": "../../../../components/proxy-host-object.json#/properties/proxy_protocol_enabled"
85+
},
86+
"loadbalancer_address": {
87+
"$ref": "../../../../components/proxy-host-object.json#/properties/loadbalancer_address"
8288
}
8389
}
8490
}
@@ -116,6 +122,8 @@
116122
"enabled": true,
117123
"hsts_enabled": false,
118124
"hsts_subdomains": false,
125+
"proxy_protocol_enabled": false,
126+
"loadbalancer_address": "",
119127
"owner": {
120128
"id": 1,
121129
"created_on": "2024-10-07T22:43:55.000Z",

backend/templates/_listen.conf

+24-10
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,34 @@
1-
listen 80;
1+
2+
{% if proxy_protocol_enabled == 1 or proxy_protocol_enabled == true -%}
3+
{% assign port_number_http = "88" -%}
4+
{% assign port_number_https = "444" -%}
5+
{% assign listen_extra_args = "proxy_protocol" -%}
6+
{% else -%}
7+
{% assign port_number_http = "80" -%}
8+
{% assign port_number_https = "443" -%}
9+
{% assign listen_extra_args = "" -%}
10+
{% endif -%}
11+
12+
listen {{ port_number_http }} {{ listen_extra_args }};
213
{% if ipv6 -%}
3-
listen [::]:80;
14+
listen [::]:{{ port_number_http }} {{ listen_extra_args }};
415
{% else -%}
5-
#listen [::]:80;
6-
{% endif %}
16+
#listen [::]:{{ port_number_http }} {{ listen_extra_args }};
17+
{% endif -%}
18+
719
{% if certificate -%}
8-
listen 443 ssl;
20+
{% capture listen_extra_args_https %}ssl {{ listen_extra_args }}{% endcapture -%}
21+
listen {{ port_number_https }} {{ listen_extra_args_https }};
922
{% if ipv6 -%}
10-
listen [::]:443 ssl;
23+
listen [::]:{{ port_number_https }} {{ listen_extra_args_https }};
1124
{% else -%}
12-
#listen [::]:443;
13-
{% endif %}
14-
{% endif %}
25+
#listen [::]:{{ port_number_https }} {{ listen_extra_args_https }};
26+
{% endif -%}
27+
{% endif -%}
28+
1529
server_name {{ domain_names | join: " " }};
1630
{% if http2_support == 1 or http2_support == true %}
1731
http2 on;
1832
{% else -%}
1933
http2 off;
20-
{% endif %}
34+
{% endif %}
+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{% if proxy_protocol_enabled == 1 or proxy_protocol_enabled == true %}
2+
{% if loadbalancer_address != '' %}
3+
set_real_ip_from {{ loadbalancer_address }};
4+
real_ip_header proxy_protocol;
5+
{% endif %}
6+
{% endif %}

backend/templates/proxy_host.conf

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ server {
1515
{% include "_exploits.conf" %}
1616
{% include "_hsts.conf" %}
1717
{% include "_forced_ssl.conf" %}
18+
{% include "_proxy_protocol.conf" %}
1819

1920
{% if allow_websocket_upgrade == 1 or allow_websocket_upgrade == true %}
2021
proxy_set_header Upgrade $http_upgrade;

backend/templates/stream.conf

+13-6
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,38 @@
11
# ------------------------------------------------------------
22
# {{ incoming_port }} TCP: {{ tcp_forwarding }} UDP: {{ udp_forwarding }}
33
# ------------------------------------------------------------
4+
{% if proxy_protocol_enabled == 1 or proxy_protocol_enabled == true -%}
5+
{% capture listen_extra_args %}proxy_protocol{% endcapture -%}
6+
{% endif -%}
47

58
{% if enabled %}
69
{% if tcp_forwarding == 1 or tcp_forwarding == true -%}
710
server {
8-
listen {{ incoming_port }};
11+
listen {{ incoming_port }} {{ listen_extra_args }};
912
{% if ipv6 -%}
10-
listen [::]:{{ incoming_port }};
13+
listen [::]:{{ incoming_port }} {{ listen_extra_args }};
1114
{% else -%}
12-
#listen [::]:{{ incoming_port }};
15+
#listen [::]:{{ incoming_port }}{{ listen_extra_args }};
1316
{% endif %}
1417

1518
proxy_pass {{ forwarding_host }}:{{ forwarding_port }};
1619

20+
{% include '_proxy_protocol.conf' %}
21+
1722
# Custom
1823
include /data/nginx/custom/server_stream[.]conf;
1924
include /data/nginx/custom/server_stream_tcp[.]conf;
2025
}
2126
{% endif %}
2227
{% if udp_forwarding == 1 or udp_forwarding == true %}
28+
{% # Proxy Protocol is not supported for UDP %}
29+
{% assign listen_extra_args = "" %}
2330
server {
24-
listen {{ incoming_port }} udp;
31+
listen {{ incoming_port }} udp {{ listen_extra_args }};
2532
{% if ipv6 -%}
26-
listen [::]:{{ incoming_port }} udp;
33+
listen [::]:{{ incoming_port }} udp {{ listen_extra_args }};
2734
{% else -%}
28-
#listen [::]:{{ incoming_port }} udp;
35+
#listen [::]:{{ incoming_port }} udp {{ listen_extra_args }};
2936
{% endif %}
3037
proxy_pass {{ forwarding_host }}:{{ forwarding_port }};
3138

docker/Dockerfile

+2-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ RUN echo "fs.file-max = 65535" > /etc/sysctl.conf \
3535
COPY docker/scripts/install-s6 /tmp/install-s6
3636
RUN /tmp/install-s6 "${TARGETPLATFORM}" && rm -f /tmp/install-s6
3737

38-
EXPOSE 80 81 443
38+
# http admin_ui http_proxy_protocol https https_proxy_protocol
39+
EXPOSE 80 81 88 443 444
3940

4041
COPY backend /app
4142
COPY frontend/dist /app/frontend

docker/dev/Dockerfile

+2-1
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,6 @@ RUN rm -f /etc/nginx/conf.d/production.conf \
3535
COPY --from=pebbleca /test/certs/pebble.minica.pem /etc/ssl/certs/pebble.minica.pem
3636
COPY --from=testca /home/step/certs/root_ca.crt /etc/ssl/certs/NginxProxyManager.crt
3737

38-
EXPOSE 80 81 443
38+
# http admin_ui http_proxy_protocol https https_proxy_protocol
39+
EXPOSE 80 81 88 443 444
3940
ENTRYPOINT [ "/init" ]

0 commit comments

Comments
 (0)