diff --git a/backend/internal/nginx.js b/backend/internal/nginx.js index 52bdd66d..bc66ecfe 100644 --- a/backend/internal/nginx.js +++ b/backend/internal/nginx.js @@ -157,7 +157,11 @@ 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}, + {stream_enable_proxy_protocol: host.stream_enable_proxy_protocol}, + {stream_allow_proxy_protocol: host.stream_allow_proxy_protocol}, + {stream_load_balancer_ip: host.stream_load_balancer_ip}, + {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/20221011000001_stream_proxy_protocol.js b/backend/migrations/20221011000001_stream_proxy_protocol.js new file mode 100644 index 00000000..f62d6f68 --- /dev/null +++ b/backend/migrations/20221011000001_stream_proxy_protocol.js @@ -0,0 +1,80 @@ +const migrate_name = 'stream_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*/) { + knex.schema.table('stream', function (stream) { + stream.dropColumn('stream_access_proxy_protocol'); + }) + .then(() => { + logger.info('[' + migrate_name + '] stream Table altered - ERRANT Column fixed!'); + }).catch((err) => { + logger.error('[' + migrate_name + '] stream Table error while removing errant column: ' + err); + }); + + logger.info('[' + migrate_name + '] Migrating PROXY_HOST Table Up...'); + knex.schema.table('proxy_host', function (proxy_host) { + proxy_host.integer('enable_proxy_protocol').notNull().unsigned().defaultTo(0); + }) + .then(() => { + logger.info('[' + migrate_name + '] proxy_host Table altered - "enable_proxy_protocol" added'); + }).catch((err) => { + logger.error('[' + migrate_name + '] proxy_host Table error migrating up: ' + err); + }); + knex.schema.table('proxy_host', function (proxy_host) { + proxy_host.string('load_balancer_ip').notNull().defaultTo(''); + }) + .then(() => { + logger.info('[' + migrate_name + '] proxy_host Table altered - "load_balancer_ip" added'); + }).catch((err) => { + logger.error('[' + migrate_name + '] proxy_host Table error migrating up: ' + err); + }); + + logger.info('[' + migrate_name + '] Migrating STREAM Table Up...'); + knex.schema.table('stream', function (stream) { + stream.integer('stream_allow_proxy_protocol').notNull().unsigned().defaultTo(0); + }) + .then(() => { + logger.info('[' + migrate_name + '] stream Table altered - "stream_allow_proxy_protocol" added'); + }).catch((err) => { + logger.error('[' + migrate_name + '] stream Table error migrating up: ' + err); + }); + knex.schema.table('stream', function (stream) { + stream.integer('stream_enable_proxy_protocol').notNull().unsigned().defaultTo(0); + }) + .then(() => { + logger.info('[' + migrate_name + '] stream Table altered - "stream_enable_proxy_protocol" added'); + }).catch((err) => { + logger.error('[' + migrate_name + '] stream Table error migrating up: ' + err); + }); + + knex.schema.table('stream', function (stream) { + stream.string('stream_load_balancer_ip').notNull().defaultTo(''); + }) + .then(() => { + logger.info('[' + migrate_name + '] stream Table altered - "stream_load_balancer_ip" added'); + }).catch((err) => { + logger.error('[' + migrate_name + '] stream Table error migrating up: ' + err); + }); + return Promise.resolve(true); +}; + +/** + * 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..74392aa5 100644 --- a/backend/schema/endpoints/proxy-hosts.json +++ b/backend/schema/endpoints/proxy-hosts.json @@ -58,6 +58,17 @@ "example": true, "type": "boolean" }, + "enable_proxy_protocol": { + "description": "Enable PROXY Protocol support (Pass through)", + "example": true, + "type": "boolean" + }, + "load_balancer_ip": { + "description": "Authorized TCP Load Balancer IP / CIDR for setting 'set_real_ip_from'", + "type": "string", + "minLength": 0, + "maxLength": 255 + }, "access_list_id": { "$ref": "../definitions.json#/definitions/access_list_id" }, @@ -155,6 +166,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 +262,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 +341,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/schema/endpoints/streams.json b/backend/schema/endpoints/streams.json index 159c8036..1eaf5b2f 100644 --- a/backend/schema/endpoints/streams.json +++ b/backend/schema/endpoints/streams.json @@ -46,6 +46,21 @@ "udp_forwarding": { "type": "boolean" }, + "stream_enable_proxy_protocol": { + "description": "Enable PROXY Protocol creation and override", + "example": true, + "type": "boolean" + }, + "stream_allow_proxy_protocol": { + "description": "Enable PROXY Protocol pass through", + "example": true, + "type": "boolean" + }, + "stream_load_balancer_ip": { + "type": "string", + "minLength": 0, + "maxLength": 255 + }, "enabled": { "$ref": "../definitions.json#/definitions/enabled" }, @@ -78,6 +93,15 @@ "udp_forwarding": { "$ref": "#/definitions/udp_forwarding" }, + "stream_allow_proxy_protocol": { + "$ref": "#/definitions/stream_allow_proxy_protocol" + }, + "stream_enable_proxy_protocol": { + "$ref": "#/definitions/stream_enable_proxy_protocol" + }, + "stream_load_balancer_ip": { + "$ref": "#/definitions/stream_load_balancer_ip" + }, "enabled": { "$ref": "#/definitions/enabled" }, @@ -88,7 +112,7 @@ "links": [ { "title": "List", - "description": "Returns a list of Steams", + "description": "Returns a list of Streams", "href": "/nginx/streams", "access": "private", "method": "GET", @@ -137,6 +161,15 @@ "udp_forwarding": { "$ref": "#/definitions/udp_forwarding" }, + "stream_allow_proxy_protocol": { + "$ref": "#/definitions/stream_allow_proxy_protocol" + }, + "stream_enable_proxy_protocol": { + "$ref": "#/definitions/stream_enable_proxy_protocol" + }, + "stream_load_balancer_ip": { + "$ref": "#/definitions/stream_load_balancer_ip" + }, "meta": { "$ref": "#/definitions/meta" } @@ -177,6 +210,15 @@ "udp_forwarding": { "$ref": "#/definitions/udp_forwarding" }, + "stream_allow_proxy_protocol": { + "$ref": "#/definitions/stream_allow_proxy_protocol" + }, + "stream_enable_proxy_protocol": { + "$ref": "#/definitions/stream_enable_proxy_protocol" + }, + "stream_load_balancer_ip": { + "$ref": "#/definitions/stream_load_balancer_ip" + }, "meta": { "$ref": "#/definitions/meta" } @@ -190,7 +232,7 @@ }, { "title": "Delete", - "description": "Deletes a existing Stream", + "description": "Deletes an existing Stream", "href": "/nginx/streams/{definitions.identity.example}", "access": "private", "method": "DELETE", @@ -204,7 +246,7 @@ }, { "title": "Enable", - "description": "Enables a existing Stream", + "description": "Enables an existing Stream", "href": "/nginx/streams/{definitions.identity.example}/enable", "access": "private", "method": "POST", @@ -218,7 +260,7 @@ }, { "title": "Disable", - "description": "Disables a existing Stream", + "description": "Disables an existing Stream", "href": "/nginx/streams/{definitions.identity.example}/disable", "access": "private", "method": "POST", diff --git a/backend/templates/_listen.conf b/backend/templates/_listen.conf index 730f3a7c..d73d9b44 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 %} {% endif %} server_name {{ domain_names | join: " " }}; diff --git a/backend/templates/_proxy_protocol.conf b/backend/templates/_proxy_protocol.conf new file mode 100644 index 00000000..cba0424f --- /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 %} diff --git a/backend/templates/_stream_proxy_protocol.conf b/backend/templates/_stream_proxy_protocol.conf new file mode 100644 index 00000000..7275e4e5 --- /dev/null +++ b/backend/templates/_stream_proxy_protocol.conf @@ -0,0 +1,5 @@ +{%if stream_allow_proxy_protocol == 1 or stream_allow_proxy_protocol == true %} +{% if stream_load_balancer_ip != '' %} + set_real_ip_from {{ stream_load_balancer_ip }}; +{% endif %} +{% endif %} diff --git a/backend/templates/dead_host.conf b/backend/templates/dead_host.conf index d94dff57..b632933b 100644 --- a/backend/templates/dead_host.conf +++ b/backend/templates/dead_host.conf @@ -6,6 +6,7 @@ server { {% include "_certificates.conf" %} {% include "_hsts.conf" %} {% include "_forced_ssl.conf" %} +{% include "_proxy_protocol.conf" %} access_log /data/logs/dead-host-{{ id }}_access.log standard; error_log /data/logs/dead-host-{{ id }}_error.log warn; diff --git a/backend/templates/default.conf b/backend/templates/default.conf index ec68530c..9099f6ef 100644 --- a/backend/templates/default.conf +++ b/backend/templates/default.conf @@ -2,19 +2,25 @@ # Default Site # ------------------------------------------------------------ {% if value == "congratulations" %} -# Skipping output, congratulations page configration is baked in. +# Skipping output, congratulations page configuration is baked in. {%- else %} server { +{% if enable_proxy_protocol == 1 or enable_proxy_protocol == true%} + listen 88 proxy_protocol; +{% if ipv6 -%} + listen [::]:88 proxy_protocol; +{% endif %} +{% else -%} listen 80 default; {% if ipv6 -%} listen [::]:80 default; -{% else -%} - #listen [::]:80 default; +{% endif %} {% endif %} server_name default-host.localhost; access_log /data/logs/default-host_access.log combined; error_log /data/logs/default-host_error.log warn; {% include "_exploits.conf" %} +{% include "_proxy_protocol.conf"} include conf.d/include/letsencrypt-acme-challenge.conf; 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/backend/templates/redirection_host.conf b/backend/templates/redirection_host.conf index 339fe72e..3e7e7eba 100644 --- a/backend/templates/redirection_host.conf +++ b/backend/templates/redirection_host.conf @@ -8,6 +8,7 @@ server { {% include "_exploits.conf" %} {% include "_hsts.conf" %} {% include "_forced_ssl.conf" %} +{% include "_proxy_protocol.conf" %} access_log /data/logs/redirection-host-{{ id }}_access.log standard; error_log /data/logs/redirection-host-{{ id }}_error.log warn; diff --git a/backend/templates/stream.conf b/backend/templates/stream.conf index 76159a64..5cce27cf 100644 --- a/backend/templates/stream.conf +++ b/backend/templates/stream.conf @@ -5,13 +5,16 @@ {% if enabled %} {% if tcp_forwarding == 1 or tcp_forwarding == true -%} server { - listen {{ incoming_port }}; + listen {{ incoming_port }}{% if stream_allow_proxy_protocol == 1 or stream_allow_proxy_protocol == true%} proxy_protocol{% endif %}; {% if ipv6 -%} - listen [::]:{{ incoming_port }}; + listen [::]:{{ incoming_port }}{% if stream_allow_proxy_protocol == 1 or stream_allow_proxy_protocol == true%} proxy_protocol{% endif %}; {% else -%} #listen [::]:{{ incoming_port }}; {% endif %} - +{%if stream_enable_proxy_protocol == 1 or stream_enable_proxy_protocol == true%} + proxy_protocol on; +{% endif %} + {% include '_stream_proxy_protocol.conf' %} proxy_pass {{ forwarding_host }}:{{ forwarding_port }}; # Custom diff --git a/docker/Dockerfile b/docker/Dockerfile index 88f0b6e8..acb59359 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -24,6 +24,7 @@ ENV SUPPRESS_NO_CONFIG_WARNING=1 \ MODSEC_ENABLE="0" \ MODSEC_ADMIN_PANEL="0" \ CROWDSEC_UPDATE_DIR='/cs-update' \ + CROWDSEC_TEMPLATES='/crowdsec/templates' \ GEOLITE_DB_GRAB="0" \ GEOLITE2_DB_GRAB="0" \ GEOIP_DIR="/geoip_db" \ 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..3b18a08e 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,13 @@ 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 +172,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 +274,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/app/nginx/stream/form.ejs b/frontend/js/app/nginx/stream/form.ejs index eb80c373..1a512a63 100644 --- a/frontend/js/app/nginx/stream/form.ejs +++ b/frontend/js/app/nginx/stream/form.ejs @@ -42,6 +42,32 @@
+
+
+ +
+
+
+
+ +
+
+
+
+ + > +
+
+ +
<%- i18n('streams', 'forward-type-error') %>
diff --git a/frontend/js/app/nginx/stream/form.js b/frontend/js/app/nginx/stream/form.js index be8fc8bc..e73335d6 100644 --- a/frontend/js/app/nginx/stream/form.js +++ b/frontend/js/app/nginx/stream/form.js @@ -18,13 +18,22 @@ module.exports = Mn.View.extend({ buttons: '.modal-footer button', switches: '.custom-switch-input', cancel: 'button.cancel', - save: 'button.save' + save: 'button.save', + stream_allow_proxy_protocol: 'input[name="stream_allow_proxy_protocol"]', + stream_load_balancer_ip: 'input[name="stream_load_balancer_ip"]' }, events: { 'change @ui.switches': function () { this.ui.type_error.hide(); }, + 'change @ui.stream_allow_proxy_protocol': function () { + let checked = this.ui.stream_allow_proxy_protocol.prop('checked'); + this.ui.stream_load_balancer_ip + .prop('disabled', !checked) + .parents('.form-group') + .css('opacity', checked ? 1 : 0.5); + }, 'click @ui.save': function (e) { e.preventDefault(); @@ -47,6 +56,8 @@ module.exports = Mn.View.extend({ data.forwarding_port = parseInt(data.forwarding_port, 10); data.tcp_forwarding = !!data.tcp_forwarding; data.udp_forwarding = !!data.udp_forwarding; + data.stream_enable_proxy_protocol = !!data.stream_enable_proxy_protocol; + data.stream_allow_proxy_protocol = !!data.stream_allow_proxy_protocol; let method = App.Api.Nginx.Streams.create; let is_new = true; @@ -82,3 +93,4 @@ module.exports = Mn.View.extend({ } } }); + diff --git a/frontend/js/i18n/messages.json b/frontend/js/i18n/messages.json index aa544c7e..8561c515 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": "Allow PROXY Protocol", + "load-balancer-ip": "Load balancer or TCP proxy IP / CIDR range" }, "redirection-hosts": { "title": "Redirection Hosts", @@ -179,7 +181,10 @@ "delete-confirm": "Are you sure you want to delete this Stream?", "help-title": "What is a Stream?", "help-content": "A relatively new feature for Nginx, a Stream will serve to forward TCP/UDP traffic directly to another computer on the network.\nIf you're running game servers, FTP or SSH servers this can come in handy.", - "search": "Search Incoming Port…" + "search": "Search Incoming Port…", + "allow-proxy-protocol": "Allow PROXY Protocol", + "enable-proxy-protocol": "Create PROXY Headers", + "load-balancer-ip": "Load balancer or TCP proxy IP / CIDR range" }, "certificates": { "title": "SSL Certificates", 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: '', diff --git a/frontend/js/models/stream.js b/frontend/js/models/stream.js index ba035429..dd238b39 100644 --- a/frontend/js/models/stream.js +++ b/frontend/js/models/stream.js @@ -13,6 +13,9 @@ const model = Backbone.Model.extend({ forwarding_port: null, tcp_forwarding: true, udp_forwarding: false, + stream_allow_proxy_protocol: false, + stream_enable_proxy_protocol: false, + stream_load_balancer_ip: '', enabled: true, meta: {}, // The following are expansions: diff --git a/scripts/frontend-build b/scripts/frontend-build index 0de8d727..2c5947fa 100755 --- a/scripts/frontend-build +++ b/scripts/frontend-build @@ -11,7 +11,9 @@ if hash docker 2>/dev/null; then docker pull "${DOCKER_IMAGE}" cd "${DIR}/.." echo -e "${BLUE}❯ ${CYAN}Building Frontend ...${RESET}" - docker run --rm -e CI=true -v "$(pwd)/frontend:/app/frontend" -v "$(pwd)/global:/app/global" -w /app/frontend "$DOCKER_IMAGE" sh -c "yarn install && yarn build && yarn build && chown -R $(id -u):$(id -g) /app/frontend" + docker run --rm -e CI=true -v "$(pwd)/frontend:/app/frontend" -v "$(pwd)/global:/app/global" \ + -w /app/frontend "$DOCKER_IMAGE" sh \ + -c "yarn install && yarn build && yarn build && chown -R $(id -u):$(id -g) /app/frontend" echo -e "${BLUE}❯ ${GREEN}Building Frontend Complete${RESET}" else echo -e "${RED}❯ docker command is not available${RESET}" diff --git a/scripts/npm_db_fix b/scripts/npm_db_fix new file mode 100755 index 00000000..b29750e1 --- /dev/null +++ b/scripts/npm_db_fix @@ -0,0 +1,11 @@ +#!/usr/bin/env sh +log() { + echo -e "[$(basename "$0")]> $*" +} + log "Executing SQL migration fixes" + mysql -u root -p"${MYSQL_ROOT_PASSWORD}" -D "${MYSQL_DATABASE}" -e "DELETE from migrations where name = '20220209144645_proxy_protocol.js';" + mysql -u root -p"${MYSQL_ROOT_PASSWORD}" -D "${MYSQL_DATABASE}" -e "DELETE from migrations where name = '22021009153423_proxy_protocol.js';" + mysql -u root -p"${MYSQL_ROOT_PASSWORD}" -D "${MYSQL_DATABASE}" -e "DELETE from migrations where name = '22021010135303_stream_proxy_protocol.js';" + mysql -u root -p"${MYSQL_ROOT_PASSWORD}" -D "${MYSQL_DATABASE}" -e "DELETE from migrations where name = '22021010135304_stream_proxy_protocol.js';" + mysql -u root -p"${MYSQL_ROOT_PASSWORD}" -D "${MYSQL_DATABASE}" -e "DELETE from migrations where name = '20221010135304_stream_proxy_protocol.js';" + mysql -u root -p"${MYSQL_ROOT_PASSWORD}" -D "${MYSQL_DATABASE}" -e "DELETE from migrations where name = '20221011000001_stream_proxy_protocol.js';"