View on GitHub

reverse-proxy-middleware

A reverse proxy blocking bot requests.

Project status

npmnpm downloads

build

check typeslinttest

build push image

code coverage

documentation website

Use case

Easy and dynamically configurable reverse proxy. This tool can act as a middleware to check incoming requests via external bot filtering services such as ReCaptcha or friendlycaptcha. Adding state via session token with external authentication apis is possible as applying any external api given data to the incoming and conditionally forwarded requests.

Quick start

Simple forwarding

Simple reverse proxy request from http://localhost:8080 to https://www.google.com without modifying the entire request.

{
  "forwarders": {
    "google": {
      "host": "www.google.com"
    }
  }
}

Since the proxy starts at localhost on port 8080 as a default configuration you can check the configuration via a simple curl command:

curl --verbose http://localhost:8080

Behind there are a some commonly use defaults configured under key "configuration" in package.json. Please have a look.

Distributing requests to different backends

Here is how to distribute incoming requests randomly between google and bing:

{
  "forwarders": {
    "bing": {
      "host": "www.bing.com",
      "useExpression": "Math.random() < 0.5"
    },

    "google": {
      "host": "www.google.com"
    }
  }
}

Forwarders are iterated in alphabetical order of their name and useExpression are getting evaluated. Since "google" is always "used" it depends on the random outcome of bing's expression if it is beeing used or not.

Since this proxy just streams the whole request through it could be used as basic load balancer with this configuration.

Rewriting headers for underlying backend

Headers can be replaced in both directions. Client-Request to forward or retrieved responses given from configured backend:

{
  "forwarders": {
    "bing": {
      "host": "www.bing.com",

      "headerTransformations": {
        "send": {
          "source": "/X-Special-Client-Header-Name: (.+)/gi",
          "target": "'New-Header-Name: $1'"
        },

        "retrieve": {
          "source": "/set-cookie: (.+)/gi",
          "target": "'X-Prevented-Cookie: $1'"
        }
      }
    }
  }
}

Test via:

  curl \
    --header 'X-Special-Client-Header-Name: value' \
    --verbose \
    http://localhost:8080 \
      1>/dev/null

You should see a lot of cookie header ("set-cookie: ..." replaced by "X-Prevented-Cookie: ...". Note that muting the standart output ("1>/dev/null") enables you to focus on retrieved headers printed via secondary error output.

State-APIs

State-APIs enables you to conditionally trigger requests to third party endpoints and use responses for further decisions how to proceed. When a state api is used for a specified request that response can be used via expressions to transform subsequent api requests, decide which backend to use or transform the final backend request.

In the following example you can see how a state api is configured to catch specific request to deal with. The last running pre expressions which results in a boolean value will trigger if the referenced state api should be used for given request.

Here is an example:

{
  "forwarders": {
    "bing": {
      "host": "www.bing.com",

      "stateAPIs": {
        "name": "sense",
        "url": "https://www.google.com/search?q=${data.question}",

        "data": {
          "question": "What is the meaning of life?"
        },

        "expressions": {
          "pre": "request.headers['ask-for-sense-of-live'] ? true : null",
          "post": "response.statusCode >= 200 && response.statusCode < 300 ? null : response.statusCode"
        }
      }
    }
  }
}

What is going on here? We generally forward requests to "www.bing.com" but if there is a header called "ask-for-sense-of-live" present in client request we will first ask google for the meaning of life. If google answers with a "negative" response code not between 200 and 300 we will just do the final forwarding to bing. If google responses in a positive manner the resulting status code we will be used for answering client and no forwarding to "www.bing.com" happens.

Here es a test curl command:

  curl \
    --header 'ask-for-sense-of-live: value' \
    --verbose \
    http://localhost:8080 \
      1>/dev/null

This should result in a simple response but:

curl --verbose http://localhost:8080 1>/dev/null

will finally request "www.bing.com".

Pre and post evaluations can have various results. The meanings of them are described here:

Pre-Evaluation Results

ResultMeaning
break (string)Do not evaluate subsequent pre evaluations.
null or undefinedJust jump to the next evaluation to run.
true (boolean)Use this state api configuration. Run the configured request.
false (boolean)Do not use this state api and to not run subsequent pre evaluations.
code (number)Answer client request with provided http status code and do not run any subsequent pre-evaluations, state-api request or request forwarding to the underlying backend.

Post-Evaluation Results

ResultMeaning
break (string)Do not evaluate subsequent post evaluations.
null or undefinedJust jump to the next evaluation to run.
code (number)Answer client request with provided http status code and do not run any subsequent post-evaluations, state-api request or request forwarding to the underlying backend.

Smart configurations

Whenever you can configure list of items you can either use just one or a list of them. Consider this configuration example:

{
  "forwarders": {
    "bing": {
      "host": "www.bing.com",

      "headerTransformations": [{...}, {...}, ...],

      "stateAPIs": {
        "expressions": {
          "pre": ["...", "...", ...],
          "post": ["...", "...", ...]
        }
      }
    }
  }
}

If only one item is needed please consider that:

{
  "forwarders": {
    "bing": {
      "host": "www.bing.com",

      "headerTransformations": [{...}],

      "stateAPIs": {
        "expressions": {
          "pre": ["..."],
          "post": ["..."]
        }
      }
    }
  }
}

is equivalent to:

{
  "forwarders": {
    "bing": {
      "host": "www.bing.com",

      "headerTransformations": {...},

      "stateAPIs": {
        "expressions": {
          "pre": "...",
          "post": "..."
        }
      }
    }
  }
}

Use environment variables

While some configuration values are interpret as expression to be evalued at runtime e.g. to decide which endpoint to use:

{
  "forwarders": {
    "endpoint": {
      ...
      "useExpression": "..."
    }
  }
}

Every item can utilize expression to dynamically derive intial configurations:

{
  "port": {
    "__evaluate__": "environment.PORT ?? 8080"
  },
  ...
}

If an environment variabel "PORT" is set it will be used or "8080" as a fallback.

Use Base Forwarder

Base forwarder are inherited by every specific forwarder. This configuration:

{
  "forwarders": {
    "base: {
      "headerTransformations": {
        "send": {
          "source": "/(GET|POST) \\/.* (.*)/",
          "target": "'$1 /sub/path/to/forward/to $2'"
        }
      }
    },

    "bing": {
      "host": "www.bing.com",
      "useExpression": "Math.random() < 0.5"
    },

    "google": {
      "host": "www.google.com"
    }
  }
}

is equivalent to:

{
  "forwarders": {
    "bing": {
      "host": "www.bing.com",

      "useExpression": "Math.random() < 0.5",

      "headerTransformations": {
        "send": {
          "source": "/(GET|POST) \\/.* (.*)/",
          "target": "'$1 /sub/path/to/forward/to $2'"
        }
      }
    },

    "google": {
      "host": "www.google.com",

      "headerTransformations": {
        "send": {
          "source": "/(GET|POST) \\/.* (.*)/",
          "target": "'$1 /sub/path/to/forward/to $2'"
        }
      }
    }
  }
}

Use base State-APIs

As we support generic base forwarder confgurations there are also base state api configuraton sections. Consider the follwing configuration example:

{
  "forwarders": {
    "bing": {
      "host": "www.bing.com",

      "stateAPIs": [
        {
          "name": "base",
          "url": "https://www.google.com/search?q=${data.query}",

          "expressions": {
            "pre": "request.headers['ask-google'] ? true : null",
            "post": "response.statusCode >= 200 && response.statusCode < 300 ? null : response.statusCode"
          }
        }

        {
          "name": "sense",

          "data": {
            "query": "What is the meaning of life?"
          }
        },

        {
          "name": "nonesense",

          "data": {
            "query": "baby cats"
          }
        }
      ]
    }
  }
}

Note that url and expression are inherited to the state apis "sense" and "nonsense". The Data field can save various configuration items to be used in runtime expressions. Please also note that it is possible to access configuration, request or response informations from other state apis in every runtime expression.

Every expression can access the following environment:

NameMeaning
dataGeneric configuration items.
errorError object if some occured.
requestClient request informations.
responseResponse informations (available in post evaluations).
stateAPIsAccess oher state api informations.
Toolssee

About this website

Provider of https://torben.website/reverse-proxy-middleware :
Torben Sickert
Waldstraße 29
791194 Gundelfingen i.Br.
Phone: +49 (0) 176 / 10 248 185
Email:
info@torben.website
Website: https://torben.website
home

Disclaimer

Liability for content

Die Inhalte unserer Seiten wurden mit größter Sorgfalt erstellt. Für die Richtigkeit, Vollständigkeit und Aktualität der Inhalte können wir jedoch keine Gewähr übernehmen. Als Diensteanbieter sind wir gemäß § 7 Abs.1 TMG für eigene Inhalte auf diesen Seiten nach den allgemeinen Gesetzen verantwortlich. Nach §§ 8 bis 10 TMG sind wir als Diensteanbieter jedoch nicht verpflichtet, übermittelte oder gespeicherte fremde Informationen zu überwachen oder nach Umständen zu forschen, die auf eine rechtswidrige Tätigkeit hinweisen. Verpflichtungen zur Entfernung oder Sperrung der Nutzung von Informationen nach den allgemeinen Gesetzen bleiben hiervon unberührt. Eine diesbezügliche Haftung ist jedoch erst ab dem Zeitpunkt der Kenntnis einer konkreten Rechtsverletzung möglich. Bei Bekannt werden von entsprechenden Rechtsverletzungen werden wir diese Inhalte umgehend entfernen.

Liability for links

Unser Angebot enthält Links zu externen Webseiten Dritter, auf deren Inhalte wir keinen Einfluss haben. Deshalb können wir für diese fremden Inhalte auch keine Gewähr übernehmen. Für die Inhalte der verlinkten Seiten ist stets der jeweilige Anbieter oder Betreiber der Seiten verantwortlich. Die verlinkten Seiten wurden zum Zeitpunkt der Verlinkung auf mögliche Rechtsverstöße überprüft. Rechtswidrige Inhalte waren zum Zeitpunkt der Verlinkung nicht erkennbar. Eine permanente inhaltliche Kontrolle der verlinkten Seiten ist jedoch ohne konkrete Anhaltspunkte einer Rechtsverletzung nicht zumutbar. Bei Bekanntwerden von Rechtsverletzungen werden wir derartige Links umgehend entfernen.

Copyright

Die durch die Seitenbetreiber erstellten Inhalte und Werke auf diesen Seiten unterliegen dem deutschen Urheberrecht. Die Vervielfältigung, Bearbeitung, Verbreitung und jede Art der Verwertung außerhalb der Grenzen des Urheberrechtes bedürfen der schriftlichen Zustimmung des jeweiligen Autors bzw. Erstellers. Downloads und Kopien dieser Seite sind nur für den privaten, nicht kommerziellen Gebrauch gestattet. Soweit die Inhalte auf dieser Seite nicht vom Betreiber erstellt wurden, werden die Urheberrechte Dritter beachtet. Insbesondere werden Inhalte Dritter als solche gekennzeichnet. Sollten Sie trotzdem auf eine Urheberrechtsverletzung aufmerksam werden, bitten wir um einen entsprechenden Hinweis. Bei Bekanntwerden von Rechtsverletzungen werden wir derartige Inhalte umgehend entfernen.

Privacy Policy

Die Nutzung unserer Webseite ist in der Regel ohne Angabe personenbezogener Daten möglich. Soweit auf unseren Seiten personenbezogene Daten (beispielsweise Name, Anschrift oder E-Mail-Adressen) erhoben werden, erfolgt dies, soweit möglich, stets auf freiwilliger Basis. Diese Daten werden ohne Ihre ausdrückliche Zustimmung nicht an Dritte weitergegeben. Wir darauf hin, dass die Datenübertragung im Internet (z.B. bei der Kommunikation per E-Mail) Sicherheitslücken aufweisen kann. Ein lückenloser Schutz der Daten vor dem Zugriff durch Dritte ist nicht möglich. Der Nutzung von im Rahmen der Impressumspflicht veröffentlichten Kontaktdaten durch Dritte zur Übersendung von nicht ausdrücklich angeforderter Werbung und Informationsmaterialien wird hiermit ausdrücklich widersprochen. Die Betreiber der Seiten behalten sich ausdrücklich rechtliche Schritte im Falle der unverlangten Zusendung von Werbeinformationen, etwa durch Spam-Mails, vor.

Privacy Statement for using Google Analytics

Diese Website benutzt Google Analytics, einen Webanalysedienst der Google Inc. ("Google"). Google Analytics verwendet sog. "Cookies", Textdateien, die auf Ihrem Computer gespeichert werden und die eine Analyse der Benutzung der Website durch Sie ermöglichen. Die durch den Cookie erzeugten Informationen über Ihre Benutzung dieser Website werden in der Regel an einen Server von Google in den USA übertragen und dort gespeichert. Im Falle der Aktivierung der IP-Anonymisierung auf dieser Webseite wird Ihre IP-Adresse von Google jedoch innerhalb von Mitgliedstaaten der Europäischen Union oder in anderen Vertragsstaaten des Abkommens über den Europäischen Wirtschaftsraum zuvor gekürzt. Nur in Ausnahmefällen wird die volle IP-Adresse an einen Server von Google in den USA übertragen und dort gekürzt. Im Auftrag des Betreibers dieser Website wird Google diese Informationen benutzen, um Ihre Nutzung der Website auszuwerten, um Reports über die Websiteaktivitäten zusammenzustellen und um weitere mit der Websitenutzung und der Internetnutzung verbundene Dienstleistungen gegenüber dem Websitebetreiber zu erbringen. Die im Rahmen von Google Analytics von Ihrem Browser übermittelte IP-Adresse wird nicht mit anderen Daten von Google zusammengeführt. Sie können die Speicherung der Cookies durch eine entsprechende Einstellung Ihrer Browser-Software verhindern; wir weisen Sie jedoch darauf hin, dass Sie in diesem Fall gegebenenfalls nicht sämtliche Funktionen dieser Website vollumfänglich werden nutzen können. Sie können darüber hinaus die Erfassung der durch das Cookie erzeugten und auf Ihre Nutzung der Website bezogenen Daten (inkl. Ihrer IP-Adresse) an Google sowie die Verarbeitung dieser Daten durch Google verhindern, indem Sie das unter dem folgenden Link verfügbare Browser-Plugin herunterladen und installieren.

Copyright Statement

Unless noted otherwise, all artwork on this website is protected property of the website author. Any use for commercial purpose, reproduction and publication requires the author's written permission. Commercial work created in cooperation or bound by contract with third parties are specifically marked. Respective copyrights apply.

top