{"id":13583039,"url":"https://github.com/jupyterhub/configurable-http-proxy","last_synced_at":"2025-05-14T01:08:57.476Z","repository":{"id":20062233,"uuid":"23330903","full_name":"jupyterhub/configurable-http-proxy","owner":"jupyterhub","description":"node-http-proxy plus a REST API","archived":false,"fork":false,"pushed_at":"2025-04-07T20:35:58.000Z","size":1423,"stargazers_count":257,"open_issues_count":22,"forks_count":132,"subscribers_count":19,"default_branch":"main","last_synced_at":"2025-04-13T04:55:04.177Z","etag":null,"topics":["chp","jupyter","jupyterhub","proxy"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jupyterhub.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2014-08-25T22:28:59.000Z","updated_at":"2025-04-08T11:05:03.000Z","dependencies_parsed_at":"2023-10-01T10:45:37.142Z","dependency_job_id":"6ade6b25-b640-40d2-a568-bbd21814ab4a","html_url":"https://github.com/jupyterhub/configurable-http-proxy","commit_stats":{"total_commits":660,"total_committers":41,"mean_commits":"16.097560975609756","dds":0.5969696969696969,"last_synced_commit":"17b5392eb7f1dd96ee6ae028d25469e4e166ba82"},"previous_names":[],"tags_count":44,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jupyterhub%2Fconfigurable-http-proxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jupyterhub%2Fconfigurable-http-proxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jupyterhub%2Fconfigurable-http-proxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jupyterhub%2Fconfigurable-http-proxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jupyterhub","download_url":"https://codeload.github.com/jupyterhub/configurable-http-proxy/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248665763,"owners_count":21142123,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chp","jupyter","jupyterhub","proxy"],"created_at":"2024-08-01T15:03:12.803Z","updated_at":"2025-04-13T04:55:08.394Z","avatar_url":"https://github.com/jupyterhub.png","language":"JavaScript","funding_links":[],"categories":["JavaScript","proxy"],"sub_categories":[],"readme":"# [configurable-http-proxy](https://github.com/jupyterhub/configurable-http-proxy)\n\n[![npm](https://img.shields.io/npm/v/configurable-http-proxy.svg?logo=npm)](https://www.npmjs.com/package/configurable-http-proxy)\n[![Docker Build status](https://img.shields.io/docker/cloud/build/jupyterhub/configurable-http-proxy?logo=docker\u0026label=build)](https://hub.docker.com/r/jupyterhub/configurable-http-proxy/tags)\n[![GitHub Workflow Status - Test](https://img.shields.io/github/actions/workflow/status/jupyterhub/configurable-http-proxy/test.yml?branch=main\u0026logo=github\u0026label=tests)](https://github.com/jupyterhub/configurable-http-proxy/actions)\n[![GitHub](https://img.shields.io/badge/issue_tracking-github-blue?logo=github)](https://github.com/jupyterhub/configurable-http-proxy/issues)\n[![Discourse](https://img.shields.io/badge/help_forum-discourse-blue?logo=discourse)](https://discourse.jupyter.org/c/jupyterhub/z2jh-k8s)\n[![Gitter](https://img.shields.io/badge/social_chat-gitter-blue?logo=gitter)](https://gitter.im/jupyterhub/jupyterhub)\n\n**configurable-http-proxy** (CHP) provides you with a way to update and manage\na proxy table using a command line interface or REST API.\nIt is a simple wrapper around [node-http-proxy][]. node-http-proxy is an HTTP\nprogrammable proxying library that supports websockets and is suitable for\nimplementing components such as reverse proxies and load balancers. By\nwrapping node-http-proxy, **configurable-http-proxy** extends this\nfunctionality to [JupyterHub] deployments.\n\n## Table of Contents\n\n- [Install](#install)\n- [Usage](#usage)\n  - [Starting the proxy](#starting-the-proxy)\n  - [Setting a default target](#setting-a-default-target)\n  - [Command-line options](#command-line-options)\n- [Using the REST API](#using-the-rest-api)\n  - [REST API Basics](#rest-api-basics)\n  - [Authenticating via passing a token](#authenticating-via-passing-a-token)\n  - [Getting the routing table](#getting-the-routing-table)\n  - [Adding new routes](#adding-new-routes)\n  - [Deleting routes](#deleting-routes)\n- [Custom error pages](#custom-error-pages)\n  - [Setting the path for custom error pages](#setting-the-path-for-custom-error-pages)\n  - [Setting a target for custom error handling](#setting-a-target-for-custom-error-handling)\n- [Host-based routing](#host-based-routing)\n- [Troubleshooting](#troubleshooting)\n\n## Install\n\nPrerequisite: [Node.js](https://nodejs.org/en/download/) ≥ 10\n\nIf you're installing `configurable-http-proxy` in Linux, you can follow [the instruction of nodesource](https://github.com/nodesource/distributions#installation-instructions) to install arbitrary version of Node.js.\n\nTo install the `configurable-http-proxy` package globally\nusing npm:\n\n```bash\nnpm install -g configurable-http-proxy\n```\n\nTo install from the source code found in this GitHub repo:\n\n```bash\ngit clone https://github.com/jupyterhub/configurable-http-proxy\ncd configurable-http-proxy\nnpm install  # Use 'npm install -g' for global install\n```\n\n[**Return to top**][]\n\n## Usage\n\nThe configurable proxy runs two HTTP(S) servers:\n\n- The **public-facing interface** to your application (controlled by `--ip`,\n  `--port`)\n  - listens on **all interfaces** by default.\n- The **inward-facing REST API** (`--api-ip`, `--api-port`)\n  - listens on localhost by default\n  - The REST API uses token authorization, where the token is set in the\n    `CONFIGPROXY_AUTH_TOKEN` environment variable.\n\n![](./doc/_static/chp.png)\n\n[**Return to top**][]\n\n### Starting the proxy\n\n```bash\nconfigurable-http-proxy [options]\n```\n\nwhere `[options]` are the command-line options described below.\n\n[**Return to top**][]\n\n### Setting a default target\n\nThe **default target** is used when a client has requested a URL for which\nthere is no routing target found in the proxy table. To set a\n**default target**, pass the command line option,\n`--default-target`, when starting the configurable proxy:\n\n```bash\nconfigurable-http-proxy --default-target=proto://host[:port]\n```\n\nFor example:\n\n```bash\nconfigurable-http-proxy --default-target=http://localhost:8888\n```\n\n[**Return to top**][]\n\n### Command-line options\n\n```\nUsage: configurable-http-proxy [options]\n\nOptions:\n  -V, --version                      output the version number\n  --ip \u003cip-address\u003e                  Public-facing IP of the proxy\n  --port \u003cn\u003e (defaults to 8000)      Public-facing port of the proxy\n  --ssl-key \u003ckeyfile\u003e                SSL key to use, if any\n  --ssl-cert \u003ccertfile\u003e              SSL certificate to use, if any\n  --ssl-ca \u003cca-file\u003e                 SSL certificate authority, if any\n  --ssl-request-cert                 Request SSL certs to authenticate clients\n  --ssl-reject-unauthorized          Reject unauthorized SSL connections (only meaningful if --ssl-request-cert is given)\n  --ssl-protocol \u003cssl-protocol\u003e      Set specific SSL protocol, e.g. TLSv1_2, SSLv3\n  --ssl-ciphers \u003cciphers\u003e            `:`-separated ssl cipher list. Default excludes RC4\n  --ssl-allow-rc4                    Allow RC4 cipher for SSL (disabled by default)\n  --ssl-dhparam \u003cdhparam-file\u003e       SSL Diffie-Helman Parameters pem file, if any\n  --api-ip \u003cip\u003e                      Inward-facing IP for API requests (default: \"localhost\")\n  --api-port \u003cn\u003e                     Inward-facing port for API requests (defaults to --port=value+1)\n  --api-ssl-key \u003ckeyfile\u003e            SSL key to use, if any, for API requests\n  --api-ssl-cert \u003ccertfile\u003e          SSL certificate to use, if any, for API requests\n  --api-ssl-ca \u003cca-file\u003e             SSL certificate authority, if any, for API requests\n  --api-ssl-request-cert             Request SSL certs to authenticate clients for API requests\n  --api-ssl-reject-unauthorized      Reject unauthorized SSL connections (only meaningful if --api-ssl-request-cert is given)\n  --client-ssl-key \u003ckeyfile\u003e         SSL key to use, if any, for proxy to client requests\n  --client-ssl-cert \u003ccertfile\u003e       SSL certificate to use, if any, for proxy to client requests\n  --client-ssl-ca \u003cca-file\u003e          SSL certificate authority, if any, for proxy to client requests\n  --client-ssl-request-cert          Request SSL certs to authenticate clients for API requests\n  --client-ssl-reject-unauthorized   Reject unauthorized SSL connections (only meaningful if --client-ssl-request-cert is given)\n  --default-target \u003chost\u003e            Default proxy target (proto://host[:port])\n  --error-target \u003chost\u003e              Alternate server for handling proxy errors (proto://host[:port])\n  --error-path \u003cpath\u003e                Alternate server for handling proxy errors (proto://host[:port])\n  --redirect-port \u003credirect-port\u003e    Redirect HTTP requests on this port to the server on HTTPS\n  --redirect-to \u003cport\u003e               Redirect HTTP requests from --redirect-port to this port\n  --pid-file \u003cpid-file\u003e              Write our PID to a file\n  --no-x-forward                     Don't add 'X-forward-' headers to proxied requests\n  --no-prepend-path                  Avoid prepending target paths to proxied requests\n  --no-include-prefix                Don't include the routing prefix in proxied requests\n  --auto-rewrite                     Rewrite the Location header host/port in redirect responses\n  --change-origin                    Changes the origin of the host header to the target URL\n  --protocol-rewrite \u003cproto\u003e         Rewrite the Location header protocol in redirect responses to the specified protocol\n  --custom-header \u003cheader\u003e           Custom header to add to proxied requests. Use same option for multiple headers (--custom-header k1:v1 --custom-header k2:v2) (default: {})\n  --insecure                         Disable SSL cert verification\n  --host-routing                     Use host routing (host as first level of path)\n  --metrics-ip \u003cip\u003e                  IP for metrics server (default: \"\")\n  --metrics-port \u003cn\u003e                 Port of metrics server. Defaults to no metrics server\n  --log-level \u003cloglevel\u003e             Log level (debug, info, warn, error) (default: \"info\")\n  --timeout \u003cn\u003e                      Timeout (in millis) when proxy drops connection for a request.\n  --proxy-timeout \u003cn\u003e                Timeout (in millis) when proxy receives no response from target.\n  --storage-backend \u003cstorage-class\u003e  Define an external storage class. Defaults to in-MemoryStore.\n  -h, --help                         display help for command\n```\n\n[**Return to top**][]\n\n## Using the REST API\n\nThe configurable-http-proxy REST API is documented and available as:\n\n- a nicely rendered, interactive version at the\n  [petstore swagger site][]\n- a [swagger specification file][] in this repo\n\n[**Return to top**][]\n\n### REST API Basics\n\n**API Root**\n\n| HTTP method | Endpoint | Function |\n| ----------- | -------- | -------- |\n| GET         | /api/    | API Root |\n\n**Routes**\n\n| HTTP method | Endpoint                 | Function                            |\n| ----------- | ------------------------ | ----------------------------------- |\n| GET         | /api/routes              | [Get all routes in routing table][] |\n| POST        | /api/routes/{route_spec} | [Add a new route][]                 |\n| DELETE      | /api/routes/{route_spec} | [Remove the given route][]          |\n\n[**Return to top**][]\n\n### Authenticating via passing a token\n\nThe REST API is authenticated via passing a token in the `Authorization`\nheader. The API is served under the `/api/routes` base URL.\n\nFor example, this `curl` command entered in the terminal\npasses this header `\"Authorization: token $CONFIGPROXY_AUTH_TOKEN\"` for\nauthentication and retrieves the current routing table from this endpoint,\n`http://localhost:8001/api/routes`:\n\n```bash\ncurl -H \"Authorization: token $CONFIGPROXY_AUTH_TOKEN\" http://localhost:8001/api/routes\n```\n\n[**Return to top**][]\n\n### Getting the routing table\n\n**Request:**\n\n    GET /api/routes[?inactive_since=ISO8601-timestamp]\n\n**Parameters:**\n\n`inactive_since`: If the `inactive_since` URL\nparameter is given as an [ISO8601](http://en.wikipedia.org/wiki/ISO_8601)\ntimestamp, only routes whose `last_activity` is earlier than the timestamp\nwill be returned. The `last_activity` timestamp is updated whenever the proxy\npasses data to or from the proxy target.\n\n**Response:**\n\n_Status code_\n\n    status: 200 OK\n\n_Response body_\n\nA JSON dictionary of the current routing table. This JSON\ndictionary _excludes_ the default route.\n\n**Behavior:**\n\nThe current routing table is returned to the user if the request is\nsuccessful.\n\n[**Return to top**][]\n\n### Adding new routes\n\nPOST requests create new routes. The body of the request should be a JSON\ndictionary with at least one key: `target`, the target host to be proxied.\n\n**Request:**\n\n    POST /api/routes/[:path]\n\n**Required input:**\n\n`target`: The host URL\n\nExample request body:\n\n```json\n{\n  \"target\": \"http://localhost:8002\"\n}\n```\n\n**Response:**\n\n    status: 201 Created\n\n**Behavior:**\n\nAfter adding the new route, any request to `/path/prefix` on the proxy's\npublic interface will be proxied to `target`.\n\n[**Return to top**][]\n\n### Deleting routes\n\n**Request:**\n\n    DELETE /api/routes/[:path]\n\n**Response:**\n\n    status: 204 No Content\n\n**Behavior:**\n\nRemoves a route from the proxy's routing table.\n\n[**Return to top**][]\n\n## Custom error pages\n\nCustom error pages can be provided when the proxy encounters an error and has\nno proxy target to handle a request. There are two typical errors that CHP may\nhit, along with their status code:\n\n- 404 error: Returned when a client has requested a URL for which there is no\n  routing target. This error **can be prevented** by setting a\n  [`default target`][] before starting the configurable-http-proxy.\n\n- 503 error: Returned when a route exists, but the upstream server isn't\n  responding. This is more common, and can be due to any number of reasons,\n  including the target service having died, not finished starting, or network\n  instability.\n\n[**Return to top**][]\n\n### Setting the path for custom error pages\n\nWhen starting the CHP, specify an error path `--error-path /usr/share/chp-errors`\nto the location of the error page:\n\n```bash\nconfigurable-http-proxy --error-path /usr/share/chp-errors\n```\n\nWhen a proxy error occurs, CHP will look in the following location for a\ncustom html error page to serve:\n\n    /usr/share/chp-errors/{CODE}.html\n\nwhere `{CODE}` is a status code number for an html page to serve. If there is\na 503 error, CHP will look for a custom error page in this location\n`/usr/share/chp-errors/503.html`.\n\nIf no custom error html file exists for the error code, CHP will use the default\n`error.html`. If you specify an error path, **make sure** you also create\na default `error.html` file.\n\n[**Return to top**][]\n\n### Setting a target for custom error handling\n\nYou can specify a target URL to use when errors occur by setting\n`--error-target {URL}` when starting the CHP.\n\nIf, for example, CHP starts with `--error-target http://localhost:1234`,\nand the proxy encounters an error, the proxy will make a GET request to\nthe `error-target` server. The GET request will be sent to the `error-target`\nserver URL, `http://localhost:1234`, appending the status code\n`/{CODE}`, and passing the failing request's URL escaped in a URL parameter:\n\n    GET /404?url=%2Fescaped%2Fpath\n\n[**Return to top**][]\n\n## Host-based routing\n\nIf the CHP is started with the `--host-routing` option, the proxy will\nuse the hostname of the incoming request to select a target.\n\nWhen using host-based routes, the API uses the target in the same way as if\nthe hostname were the first part of the URL path, e.g.:\n\n```python\n{\n  \"/example.com\": \"https://localhost:1234\",\n  \"/otherdomain.biz\": \"http://10.0.1.4:5555\",\n}\n```\n\n[**Return to top**][]\n\n## Troubleshooting\n\nQ: My proxy is not starting. What could be happening?\n\n- If this occurs on Ubuntu/Debian, check that the you are using a recent\n  version of node. Some versions of Ubuntu/Debian come with a version of node\n  that is very old, and it is necessary to update node to a recent or `LTS`\n  version.\n\n[**Return to top**][]\n\n[node-http-proxy]: https://github.com/nodejitsu/node-http-proxy\n[jupyterhub]: https://github.com/jupyterhub/jupyterhub\n[petstore swagger site]: http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyterhub/configurable-http-proxy/HEAD/doc/rest-api.yml#/default\n[swagger specification file]: https://github.com/jupyterhub/configurable-http-proxy/blob/HEAD/doc/rest-api.yml\n[get all routes in routing table]: #getting-the-routing-table\n[add a new route]: #adding-new-routes\n[remove the given route]: #deleting-routes\n[`default target`]: #setting-a-default-target\n[**return to top**]: #table-of-contents\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjupyterhub%2Fconfigurable-http-proxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjupyterhub%2Fconfigurable-http-proxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjupyterhub%2Fconfigurable-http-proxy/lists"}