{"id":26186961,"url":"https://github.com/ivarref/mikkmokk-proxy","last_synced_at":"2025-10-23T19:57:09.368Z","repository":{"id":38342338,"uuid":"502093393","full_name":"ivarref/mikkmokk-proxy","owner":"ivarref","description":"Fault injection for the HTTP layer. A HTTP chaos proxy.","archived":false,"fork":false,"pushed_at":"2024-05-06T16:54:16.000Z","size":88,"stargazers_count":19,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-10-18T20:11:24.945Z","etag":null,"topics":["chaos-monkey","chaos-proxy","fault-injection","http","http-proxy","proxy","reverse-proxy"],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"epl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ivarref.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"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":"2022-06-10T15:30:59.000Z","updated_at":"2025-04-07T13:39:19.000Z","dependencies_parsed_at":"2024-05-06T17:53:41.746Z","dependency_job_id":"722af1cb-785f-4b49-bed6-bf2e14c6d189","html_url":"https://github.com/ivarref/mikkmokk-proxy","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/ivarref/mikkmokk-proxy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivarref%2Fmikkmokk-proxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivarref%2Fmikkmokk-proxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivarref%2Fmikkmokk-proxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivarref%2Fmikkmokk-proxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ivarref","download_url":"https://codeload.github.com/ivarref/mikkmokk-proxy/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivarref%2Fmikkmokk-proxy/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":280684029,"owners_count":26372970,"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","status":"online","status_checked_at":"2025-10-23T02:00:06.710Z","response_time":142,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["chaos-monkey","chaos-proxy","fault-injection","http","http-proxy","proxy","reverse-proxy"],"created_at":"2025-03-11T23:35:50.963Z","updated_at":"2025-10-23T19:57:09.352Z","avatar_url":"https://github.com/ivarref.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# mikkmokk-proxy\n\nmikkmokk-proxy is an unobtrusive reverse proxy server that injects faults on the HTTP layer.\n\nHave you ever wanted to test how well your (backend|frontend) services handles\n* failed requests\n* duplicate requests\n* delayed requests\n\nmikkmokk-proxy is — literally — a gateway drug for resiliency testing on the HTTP layer.\n\n## Overview\n\n```mermaid\nsequenceDiagram\n    client-\u003e\u003emikkmokk: POST\n    mikkmokk-\u003e\u003emikkmokk: 💤delay before?💤\n    mikkmokk-\u003e\u003eclient: 💥fail before?💥\n    mikkmokk-\u003e\u003edestination: POST\n    mikkmokk-\u003e\u003edestination: 💥duplicate POST?💥\n    destination-\u003e\u003edatabase: read and/or state change\n    database-\u003e\u003edestination: result\n    destination-\u003e\u003emikkmokk: result\n    mikkmokk-\u003e\u003emikkmokk: 💤delay after?💤\n    mikkmokk-\u003e\u003eclient: result OR 💥fail after?💥\n```\n\n`client` here is anything that will normally access `destination`\nusing the HTTP protocol, but goes via `mikkmokk` instead.\n\nmikkmokk can inject five different types of faults:\n* fail a request before the destination is reached\n* fail a request after the destination is reached\n* add a delay before accessing the destination\n* add a delay after accessing the destination\n* add a duplicate a request\n\nmikkmokk does fault injection based on a percentage chance.\nThe scope for fault injection may be narrowed further by settings\nvarious matching criteria (URI, request method, header name/value pair, etc).\n\nThe percentage chances, and related settings, can be \nset both statically and dynamically:\n* Using proxy headers `x-mikkmokk-...` when accessing the reverse proxy.\n* At runtime using the admin API, both for setting new defaults and for introducing one-off errors.\n* At startup time using environment variables.\n\nmikkmokk supports proxying to arbitrary URLs.\n\n## Example usage\n\n#### Start the reverse proxy\n\nThe following setup proxies to `http://example.com`:\n```bash\n$ docker run --rm --name mikkmokk-proxy \\\n  -e DESTINATION_URL=http://example.com \\\n  -e PROXY_BIND=0.0.0.0 \\\n  -e PROXY_PORT=8080 \\\n  -e ADMIN_BIND=0.0.0.0 \\\n  -e ADMIN_PORT=7070 \\\n  -p 8080:8080 \\\n  -p 7070:7070 \\\n  docker.io/ivarref/mikkmokk-proxy:v0.1.63\n```\n\nThere are two ports being exposed:\n* The reverse proxy on port 8080.\n* The admin server on port 7070.\n\n#### Issue a regular request\n\n```\n$ curl http://localhost:8080\n...\n    \u003ch1\u003eExample Domain\u003c/h1\u003e\n    \u003cp\u003eThis domain is for use in illustrative examples in documents. You may use this\n    domain in literature without prior coordination or asking for permission.\u003c/p\u003e\n    \u003cp\u003e\u003ca href=\"https://www.iana.org/domains/example\"\u003eMore information...\u003c/a\u003e\u003c/p\u003e\n...\n```\nThis request succeeded because mikkmokk was not told to do any fault injection.\n\n#### Insert a failure before a request reaches the destination\n\nThe header `x-mikkmokk-fail-before-percentage` can be used to simulate that\nthe destination could not be reached. If present, it must be an int in the range\n\\[0, 100\\], i.e. it's the percentage chance that a request fails.\nThe default value for this header is `0`. \nThe value `100` means that the request will always fail.\nThis can be used to test if clients are retrying or not.\n\n```\n$ curl -v -H 'x-mikkmokk-fail-before-percentage: 100' http://localhost:8080\n...\n\u003c HTTP/1.1 503 Service Unavailable\n\u003c Content-Type: application/json\n...\n{\"error\":\"fail-before\"}\n```\n\nThe default HTTP status code for this is `503`, and may be changed\nusing the header `x-mikkmokk-fail-before-code`. \n\n#### Insert a failure after a request has been processed by the destination\n\nThe header `x-mikkmokk-fail-after-percentage` can be used to simulate that the \ndestination has received and processed the request, but\nthat the network between the proxy and the destination failed before\nthe proxy received the response. Thus, the client will receive an incorrect response.\nIf the client retries, will the backend handle a duplicate request?\n\n```\n$ curl -v -H 'x-mikkmokk-fail-after-percentage: 100' http://localhost:8080\n...\n\u003c HTTP/1.1 502 Bad Gateway\n\u003c Content-Type: application/json\n...\n{\"error\":\"fail-after\",\"destination-response-code\":200}\n```\n\nThe field `destination-response-code` states which HTTP status code the destination\nactually responded with.\nThe default HTTP status code for this is `502`, and may be changed using the header `x-mikkmokk-fail-after-code`.\n\n#### Insert a duplicate request\n\nThe header `x-mikkmokk-duplicate-percentage` instructs mikkmokk to make two identical, parallel requests.\n\n```\n$ curl -H 'x-mikkmokk-duplicate-percentage: 100' http://localhost:8080\n\n# In the mikkmokk logs you will see something like:\n\u003e Duplicate request returned identical HTTP status code 200 for GET http://example.com/\n```\n\n#### Only match a specific URI and/or request method\n\n```\n$ curl -H 'x-mikkmokk-match-uri: /something' \\\n       -H 'x-mikkmokk-match-method: GET' \\\n       -H 'x-mikkmokk-fail-before-percentage: 100' \\\n       http://localhost:8080/something\n{\"error\":\"fail-before\"}\n```\n\nThe default value of the `x-mikkmokk-match-uri` and `x-mikkmokk-match-method` headers is `*`, meaning that all URIs and all request methods will match.\n\nIf you only want to match a given URI prefix, you may use the `x-mikkmokk-match-uri-starts-with` header.\n\n#### Only match a given header name/value pair\n\n```\n$ curl -H 'x-mikkmokk-match-header-name: x-some-header' \\\n       -H 'x-mikkmokk-match-header-value: foobar' \\\n       -H 'x-mikkmokk-fail-before-percentage: 100' \\\n       http://localhost:8080/\n... request succeeds, header-name and -value did not match.\n\n$ curl -H 'x-mikkmokk-match-header-name: x-some-header' \\\n       -H 'x-mikkmokk-match-header-value: foobar' \\\n       -H 'x-mikkmokk-fail-before-percentage: 100' \\\n       -H 'x-some-header: foobar' \\\n       http://localhost:8080/\n{\"error\":\"fail-before\"}\n```\n\nHere we see that the first request did not fail, and thus `x-mikkmokk-match-header-name` and\n`x-mikkmokk-header-value` did not match. \n\nOn the second request it does fail however, and\nthus the header name-value pair did match. \nWe explicitly set `x-some-header` ourselves.\nIn a more real world setting it would be set by some gateway.\n\n#### Inserting delays\n\nDelays may be inserted using `x-mikkmokk-delay-before-percentage` and\n`x-mikkmokk-delay-before-ms`:\n\n```\n$ time curl -H 'x-mikkmokk-delay-before-percentage: 100' \\\n            -H 'x-mikkmokk-delay-before-ms: 3000' \\\n            http://localhost:8080\n...\nreal    0m3.252s\n```\n\nThis delay will be inserted before the destination service is accessed.\n\nIt's also possible to inject delays after the destination service has\nbeen accessed using `x-mikkmokk-delay-after-percentage` and\n`x-mikkmokk-delay-after-ms`.\n\n### Use the admin API to introduce one-off errors\n\nLet's say that you want to test how a frontend handles a failed request,\nbut you do not want edit the source code of the frontend. You also\ndo not want to create any unnecessary errors.\n\nYou can use the admin API for one-off errors for these tasks: \n\n```\n# Notice the port 7070 here, which is where we exposed the admin\n# API earlier:\n$ curl -XPOST -H 'x-mikkmokk-fail-before-percentage: 100' \\\n        http://localhost:7070/api/v1/one-off\n{\"service\":\"mikkmokk\",\"message\":\"Added one-off\"}\n\n# The next request now fails:\n$ curl http://localhost:8080\n{\"error\":\"fail-before\"}\n\n# The request after succeeds:\n$ curl http://localhost:8080\n...\u003ch1\u003eExample Domain\u003c/h1\u003e...\n```\n\nThe one-off API also supports matching on URI, request method,\nheaders, etc.\n\n\n### Use the admin API to change defaults at runtime\n\nThe admin API, running on port 7070 in this example, can be\nused to change the default headers for the runtime of the proxy.\n\n```\n$ curl -XPOST -H 'x-mikkmokk-fail-before-percentage: 20' http://localhost:7070/api/v1/update\n{\"delay-after-ms\":0,\n \"delay-after-percentage\":0,\n \"delay-before-ms\":0,\n \"delay-before-percentage\":0,\n \"destination-url\":\"http://example.com\",\n \"duplicate-percentage\":0,\n \"fail-after-code\":502,\n \"fail-after-percentage\":0,\n \"fail-before-code\":503,\n \"fail-before-percentage\":20,    # \u003c-- fail-before-percentage now has a new default value\n \"match-header-name\":\"*\",\n \"match-header-value\":\"*\",\n \"match-host\":\"*\",\n \"match-method\":\"*\",\n \"match-uri\":\"*\",\n \"match-uri-starts-with\":\"*\"}\n\n# Using the hey load generator https://github.com/rakyll/hey, \n# we can test if 20% of requests fail:\n$ hey -n 100 http://localhost:8080\n...\nStatus code distribution:\n  [200] 78 responses\n  [503] 22 responses\n\n# List current settings\n$ curl http://localhost:7070/api/v1/list\n{\"delay-after-ms\":0,\n \"delay-after-percentage\":0,\n \"delay-before-ms\":0,\n \"delay-before-percentage\":0,\n \"destination-url\":\"http://example.com\",\n \"duplicate-percentage\":0,\n \"fail-after-code\":502,\n \"fail-after-percentage\":0,\n \"fail-before-code\":503,\n \"fail-before-percentage\":20,\n \"match-header-name\":\"*\",\n \"match-header-value\":\"*\",\n \"match-host\":\"*\",\n \"match-method\":\"*\",\n \"match-uri\":\"*\",\n \"match-uri-starts-with\":\"*\"}\n \n# Reset the admin settings\n$ curl -XPOST http://localhost:7070/api/v1/reset\n{\"delay-after-ms\":0,\n \"delay-after-percentage\":0,\n \"delay-before-ms\":0,\n \"delay-before-percentage\":0,\n \"destination-url\":\"http://example.com\",\n \"duplicate-percentage\":0,\n \"fail-after-code\":502,\n \"fail-after-percentage\":0,\n \"fail-before-code\":503,\n \"fail-before-percentage\":0,    # \u003c-- fail-before-percentage now has the environment default\n \"match-header-name\":\"*\",\n \"match-header-value\":\"*\",\n \"match-host\":\"*\",\n \"match-method\":\"*\",\n \"match-uri\":\"*\",\n \"match-uri-starts-with\":\"*\"}\n\n$ hey -n 100 http://localhost:8080\n...\nStatus code distribution:\n  [200] 100 responses\n```\n\n### Proxying to arbitrary URLs\n\nmikkmokk supports a flexible URL proxying scheme.\nYou do not need to create a single mikkmokk instance for every service you want to \nproxy to.\nInstead you can tell mikkmokk where to forward to using the URI:\n\n```\n$ curl http://localhost:8080/mikkmokk-forward-http/example.org\n... \u003ch1\u003eExample Domain\u003c/h1\u003e\n\n# https scheme is also supported\n$ curl http://localhost:8080/mikkmokk-forward-https/example.org/some-other-endpoint\n... \u003ch1\u003eExample Domain\u003c/h1\u003e\n```\n\n### Headers modified by mikkmokk\n\nmikkmokk will automatically edit the `host` HTTP header when accessing the destination.\nIt will also update the `origin` and `Access-Control-Allow-Origin` HTTP headers if present.\n\n### All settings and default values\n\n| Header name             | Description                                                                                                                                                                      | Default value |\n|-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------|\n| delay-after-ms          | Number of milliseconds to delay after the destination has replied                                                                                                                | 0             |\n| delay-after-percentage  | Percentage chance of introducing delay after the destination has replied                                                                                                         | 0             |\n| delay-before-ms         | Number of milliseconds to delay before accessing the destination                                                                                                                 | 0             |\n| delay-before-percentage | Percentage chance of introducing delay before accessing the destination                                                                                                          | 0             |\n| destination-url         | Where to forward the request to. E.g. http://example.com                                                                                                                         | nil           |\n| duplicate-percentage    | Percentage chance of introducing a duplicate request                                                                                                                             | 0             |\n| fail-after-code         | The HTTP status code to reply with if a request was deliberately aborted after accessing the destination                                                                         | 502           |\n| fail-after-percentage   | Percentage chance of aborting the request after accessing the destination                                                                                                        | 0             |\n| fail-before-code        | The HTTP status code to reply with if a request was deliberately aborted before accessing the destination                                                                        | 503           |\n| fail-before-percentage  | Percentage chance of aborting the request before accessing the destination                                                                                                       | 0             |\n| match-header-name       | Only apply failures and/or delays if this HTTP header name's value is identical to ...                                                                                           | *             |\n| match-header-value      | the value in this header. I.e. use this pair of headers to match an arbitrary header value.                                                                                      | *             |\n| match-host              | Only apply failures and/or delays if the destination host matches this value, e.g. `example.org`                                                                                 | *             |\n| match-method            | Only apply failures and/or delays to this HTTP method (GET, POST, HEAD, etc.)                                                                                                    | *             |\n| match-uri               | Only apply failures and/or delays to this HTTP uri (e.g. `/my-api/my-endpoint`)                                                                                                  | *             |\n| match-uri-regex         | Only apply failures and/or delays to this HTTP uri if it matches the entire regex. Tip: an uuid may be matched with the following: `([a-f0-9]{8}(-[a-f0-9]{4}){3}-[a-f0-9]{12})` | *             |\n| match-uri-starts-with   | Only apply failures and/or delays if the HTTP uri starts with this prefix                                                                                                        | *             |\n\nWhen using these settings as headers, you will need to prefix them with `x-mikkmokk-`.\n\nFor environment variables, you will need to upper case them and replace dash with underscore, e.g.\n`destination-url` should become `DESTINATION_URL`.\n\n## NAQ\n\n\u003e Should I run mikkmokk-proxy on a public, untrusted network?\n\nNo.\n\n\u003e Should I run mikkmokk-proxy in production?\n\nNo.\n\n\u003e Can the logger show the time in my timezone?\n\nYes. Set the environment property `TZ` to your timezone, e.g. `Europe/Oslo`.\n\n\u003e NAQ?\n\nYes, that's Never Asked Questions. ¯\\\\\\_(ツ)\\_/¯\n\n## Limitations\nNo TLS/SSL support for the proxy server (bind).\nNo WebSocket support. No SSE.\n\nThere is no attempt at validating `-percentage` nor `-code` properties.\n`-percentage` should be [0, 100], and `-code` should be [200, 600).\n\n## Alternatives and related software\n\n[envoyproxy](https://www.envoyproxy.io/) has a [fault injection filter](https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/fault_filter#config-http-filters-fault-injection) that seems equivalent to `x-mikkmokk-fail-before-` headers.\n\n[mefellows/muxy](https://github.com/mefellows/muxy): Chaos engineering tool for simulating real-world distributed system failures.\n\n[bouncestorage/chaos-http-proxy](https://github.com/bouncestorage/chaos-http-proxy):  Introduce failures into HTTP requests via a proxy server.\n\n[clusterfk/chaos-proxy](https://github.com/clusterfk/chaos-proxy): ClusterFk Chaos Proxy is an unreliable HTTP proxy you can rely on.\n\n[toxiproxy](https://github.com/Shopify/toxiproxy): A chaotic TCP proxy.\n\n## Changelog\n\n#### 2024-05-06 v0.1.63\n* [Publish multiarch Docker image #1](https://github.com/ivarref/mikkmokk-proxy/issues/1).\n* Bump JDK version.\n\n#### 2023-05-12 v0.1.59\nIf remote server sends header `Access-Control-Allow-Origin` in its response,\nset it to the input value of `Origin`.\n\n#### 2022-06-23 v0.1.54\nRemove logger name.\n\n#### 2022-06-23 v0.1.53\nRemove thread name from logging, add information about timezone when logging.\n\n#### 2022-06-23 v0.1.52\nAdd coloring of HTTP status codes.\n\n#### 2022-06-19 v0.1.50\nAdd `x-mikkmokk-match-uri-regex` header.\n\n#### 2022-06-16 v0.1.42\nFirst publicly announced release.\n\n## License\n\nCopyright © 2022 Ivar Refsdal\n\nThis program and the accompanying materials are made available under the\nterms of the Eclipse Public License 2.0 which is available at\nhttp://www.eclipse.org/legal/epl-2.0.\n\nThis Source Code may also be made available under the following Secondary\nLicenses when the conditions for such availability set forth in the Eclipse\nPublic License, v. 2.0 are satisfied: GNU General Public License as published by\nthe Free Software Foundation, either version 2 of the License, or (at your\noption) any later version, with the GNU Classpath Exception which is available\nat https://www.gnu.org/software/classpath/license.html.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fivarref%2Fmikkmokk-proxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fivarref%2Fmikkmokk-proxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fivarref%2Fmikkmokk-proxy/lists"}