{"id":30076560,"url":"https://github.com/f0903/reservoir","last_synced_at":"2026-05-02T22:01:25.182Z","repository":{"id":301236552,"uuid":"1008589814","full_name":"F0903/reservoir","owner":"F0903","description":"A caching and coalescing MITM (Man-in-the-Middle) HTTP(S) forward proxy with an embedded dashboard.","archived":false,"fork":false,"pushed_at":"2026-04-30T21:22:20.000Z","size":1596,"stargazers_count":10,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-30T22:22:51.539Z","etag":null,"topics":["apt","apt-cache","apt-cacher-ng","apt-proxy","caching-proxy","docker-cache","docker-proxy","go","proxy","svelte"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/F0903.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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-06-25T19:29:09.000Z","updated_at":"2026-04-30T21:21:28.000Z","dependencies_parsed_at":"2025-06-27T21:30:19.964Z","dependency_job_id":"ca6792a9-edbc-407e-ac93-cf08d8626bb8","html_url":"https://github.com/F0903/reservoir","commit_stats":null,"previous_names":["f0903/mitm_proxy","f0903/apt-cacher-go","f0903/reservoir"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/F0903/reservoir","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/F0903%2Freservoir","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/F0903%2Freservoir/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/F0903%2Freservoir/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/F0903%2Freservoir/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/F0903","download_url":"https://codeload.github.com/F0903/reservoir/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/F0903%2Freservoir/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32550914,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-02T21:31:48.061Z","status":"ssl_error","status_checked_at":"2026-05-02T21:31:46.574Z","response_time":132,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["apt","apt-cache","apt-cacher-ng","apt-proxy","caching-proxy","docker-cache","docker-proxy","go","proxy","svelte"],"created_at":"2025-08-08T15:57:42.059Z","updated_at":"2026-05-02T22:01:25.175Z","avatar_url":"https://github.com/F0903.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# reservoir\n\n[![CI](https://github.com/F0903/reservoir/actions/workflows/ci.yml/badge.svg)](https://github.com/F0903/reservoir/actions/workflows/ci.yml)\n\nA caching and coalescing MITM (Man-in-the-Middle) HTTP(S) forward proxy with an embedded dashboard.\n\nSupports caching of both HTTP and HTTPS requests by injecting a certificate to decrypt and cache the data before sending it back to the client.\n\nThe original intended usage is as a central cache proxy for apt or other package managers when spread across multiple containers.\n\nThe dashboard is directly embedded into the executable, so the final build artifact is a single self-contained executable.\n\n## Requirements\n\n- Go 1.26 or newer\n- OpenSSL (for generating CA cert/key)\n\n## Usage Guide\n\nTo start with, you need to generate a CA certificate and key to be used as your own makeshift certificate authority to generate new certificates for requests to HTTPS domains. This is the mechanism that allows the proxy to decrypt and cache HTTPS responses, with the caveat being that EVERY client that proxies HTTPS requests through this MUST trust this CA certificate, otherwise you will get errors relating to the untrusted cert.\n\n### Generate a CA Certificate and Key\n\nThis generates a CA certificate with the common name (CN) \"reservoir\" and corresponding key, both in PEM format.\n\n```sh\nopenssl genrsa -out ca.key 2048\nopenssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 -out ca.crt -subj \"//CN=reservoir\"\n```\n\n### Trust the CA Certificate\n\n- **Linux:** Add to `/usr/local/share/ca-certificates/` and run `sudo update-ca-certificates`.\n- **Windows:** Double-click `ca.crt`, click \"Install Certificate...\" and follow the wizard.\n\n## Running the Proxy\n\nTo run the proxy you have two options; you can either download a prebuilt binary from the releases page (or an unstable build from the actions page), or you can build it yourself by following the instructions below:\n\n### Building the Proxy\n\nBefore getting started, you will need to install a few dependencies:\n\n#### Installing dependencies\n\nFirst off you will need to have [**Node.js** installed](https://nodejs.org/en/download) and **pnpm** enabled *(run the command `corepack enable pnpm`)*.\n\nThen you need to have **GNU make** installed.\nThe way to do this will vary depending on your OS. If you use a Linux distro it will be easy to install via your package manager (it might even be preinstalled).\n\nOn Windows the easiest way to do this is with [Chocolatey](https://chocolatey.org/install#individual) by running `choco install make`.  \nAlternatively you can [install it manually here](https://gnuwin32.sourceforge.net/packages/make.htm).\n\nYou will of course also need to have [Go installed](https://go.dev/dl/).\n\nThen you just have to build the project with **make** by running `make` in the project directory.\n\nThis will automatically build the frontend and the final proxy executable.\n\nThe resulting executable is now ready in the project root to be copied standalone to wherever you wish.   \nIf you are running it on Linux, you can also setup a systemd service for it, which is recommended.\n\n## Proxy Configuration\n\nConfiguration can be done either via the generated configuration file, or the command-line arguments.\n\nIf a setting is both specified in the configuration file and as a command-line argument, the command-line argument will take precedence.\n\n### Configuration File\n\nThe configuration file is a JSON file that contains all the settings for the proxy.\nYou can edit this file manually in ``var/config.json`` to change the configuration. If the ``var/`` folder or config does not exist, run the proxy once, and it will be created automatically.\nSome settings can also be changed in the Dashboard.\n\n### Dashboard Bootstrap Login\n\nWhen the API and dashboard are enabled and the user database is empty, Reservoir starts in first-run bootstrap mode.\n\nThe first admin username can be chosen during setup. The bootstrap password must be at least 12 characters, is never written to disk, and the created user is signed in immediately after setup. Once a user exists, the bootstrap endpoint returns a conflict and normal login is required.\n\nIf the API is disabled, Reservoir cannot create dashboard users or accept dashboard logins.\n\n### Package Cache Behavior\n\nReservoir is tuned first as a shared package cache for package-manager traffic. By default the proxy cache policy favors useful package caching over strict upstream cache directives:\n\n- `proxy.cache_policy.ignore_cache_control` defaults to `true`, so package responses can still be cached when upstream sends directives such as `no-store`.\n- `proxy.cache_policy.force_default_max_age` defaults to `true`, so cached responses use `proxy.cache_policy.default_max_age` instead of upstream freshness metadata.\n- Requests containing `Authorization` or `Cookie` are not stored in the shared cache.\n- Responses with `Set-Cookie`, unsupported `Vary`, or unsafe content encoding metadata are not stored in the shared cache.\n- When a cached package response is stale and upstream revalidation fails with a server error or network failure, Reservoir serves the stale cached response.\n\nThese defaults are intentional for package-cache deployments. If you need stricter general-purpose proxy semantics, disable `ignore_cache_control` and `force_default_max_age` in `var/config.json`.\n\n### Cache Backends\n\nReservoir supports two cache backends:\n\n- `cache.type = \"memory\"` keeps cached responses in process memory. This is the default and is best for short-lived burst caching where the proxy only needs to coalesce many package-manager requests that happen close together.\n- `cache.type = \"file\"` stores cached response bodies under `cache.file.dir`. This is useful when cached package responses may be larger than the memory budget or when short restart continuity is useful.\n\nThe file cache writes metadata sidecars next to cached response bodies. On startup, Reservoir loads sidecars only when the matching cached body still exists, the body is non-empty, and the cached response has not expired. Expired, corrupt, or orphaned cache files are discarded. This preserves useful restart continuity without turning the proxy into a long-lived package repository.\n\nLoaded file-cache entries are still subject to `cache.max_cache_size`, normal expiry, and the cleanup interval. If restored entries exceed the configured cache size, startup eviction trims them before serving traffic.\n\n### Command-Line Arguments\n\nYou can always display info about the command-line arguments by running the proxy with the `--help` flag. Command-line arguments only override the generated configuration when they are supplied.\n\nThe command-line arguments currently available are the following:\n\n- **version** - Print the Reservoir version and exit.\n- **listen** (:9999) - The address and port that the proxy will listen on.\n- **ca-cert** (ssl/ca.crt) - The path to the PEM cert of the CA the proxy will use to sign.\n- **ca-key** (ssl/ca.key) - The path to the PEM key of the CA the proxy will use to sign.\n- **cache-dir** (var/cache/) - The path where the file cache should be stored.\n- **webserver-listen** (localhost:8080) - The address and port that the webserver (dashboard and API) will listen on.\n- **no-dashboard** (false) - Disable the embedded dashboard.\n- **no-api** (false) - Disable the API.\n- **log-level** (info) - Set the logging level (DEBUG, INFO, WARN, ERROR).\n- **log-file** (var/proxy.log) - The path to the log file. Setting this to an empty value disables file logging and the dashboard log viewer.\n- **log-file-max-size** (500M) - The maximum size of the log file before it is rotated.\n- **log-file-max-backups** (3) - The maximum number of old log files to keep.\n- **log-file-compress** (true) - Enable compression for rotated log files.\n- **log-to-stdout** (false) - Enable logging to stdout.\n\nOther cache settings are currently configured through `var/config.json` or the dashboard rather than command-line flags. The most important ones are:\n\n- `cache.type` - `memory` or `file`.\n- `cache.max_cache_size` - Maximum total cache size.\n- `cache.cleanup_interval` - How often expired entries and over-budget cache data are cleaned up.\n- `cache.memory.memory_budget_percent` - Memory-cache budget as a percentage of total system memory.\n- `proxy.cache_policy.ignore_cache_control` - Whether to ignore upstream cache-control directives.\n- `proxy.cache_policy.force_default_max_age` - Whether to always use Reservoir's configured default freshness lifetime.\n- `proxy.cache_policy.default_max_age` - The fallback/default freshness lifetime for cached responses.\n\n## Example: Using curl with the Proxy\n\n```sh\ncurl -x http://127.0.0.1:9999 https://example.com/\n```\n\nIf your CA is not trusted by the system, you can specify it for curl:\n\n```sh\ncurl --cacert ca-cert.pem -x http://127.0.0.1:9999 https://example.com/\n```\n\nAlternatively if you are too lazy to specify the cert (like me), you can use the `-k` option to skip cert validation:\n\n```sh\ncurl -k -x http://127.0.0.1:9999 https://example.com/\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ff0903%2Freservoir","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ff0903%2Freservoir","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ff0903%2Freservoir/lists"}