decompressor is a small reverse proxy that sits in front of upstream services or intermediate proxies that do not correctly support compressed HTTP request bodies.
Its main job is to normalize incoming request bodies before they reach the next hop:
- if the incoming request body uses
Content-Encoding: gzip,decompressorwill stream-decompress it before forwarding upstream - if the incoming request body is not compressed,
decompressorforwards it as-is - upstream responses are streamed back to the client unchanged
If your original docker-compose.yml looked like this:
services:
upstream-service:
image: your/upstream-image:latest
container_name: upstream-service
restart: unless-stopped
ports:
- "127.0.0.1:5505:8080"then the host port 5505 was pointing directly to the upstream service.
With this project, decompressor takes over that public port, and the upstream service stays internal.
Use this project directory as the compose root and run:
services:
upstream-service:
image: your/upstream-image:latest
container_name: upstream-service
restart: unless-stopped
expose:
- "8080"
decompressor:
image: ghcr.io/550w-host/decompressor:latest
container_name: decompressor
restart: unless-stopped
depends_on:
- upstream-service
environment:
DECOMPRESSOR_LISTEN_ADDR: 0.0.0.0:5505
DECOMPRESSOR_UPSTREAM_URL: http://upstream-service:8080
ports:
- "127.0.0.1:5505:5505"That same setup is also included in docker-compose.yml.
git clone https://github.com/550W-HOST/decompressor.git
cd decompressorClient traffic now flows like this:
client -> localhost:5505 -> decompressor -> upstream-service:8080
Request handling rules:
Content-Encoding: gzip: streamed through a gzip decoder, then forwarded upstream without theContent-Encodingheader- no request compression: forwarded directly
- the original
Hostheader is preserved when forwarding to the upstream X-Forwarded-For,X-Forwarded-Proto, andX-Forwarded-Hostare attached for the upstream- responses: streamed straight back to the client
decompressor reads its runtime settings from environment variables.
In Docker Compose, the service definition passes the DECOMPRESSOR_* values directly with
environment:.
In local development and the external CPA tests, the easiest way is to keep values in .env.
Example:
TEST_API_BASE=https://your-api.example.com
TEST_API_KEY=your_api_key_here
TEST_MODEL=gpt-5.2
DECOMPRESSOR_LISTEN_ADDR=0.0.0.0:5505
DECOMPRESSOR_UPSTREAM_URL=http://upstream-service:8080The sample values are also present in .env.example.
Start everything:
docker compose up -dOnce it is running, point your client at:
http://127.0.0.1:5505
Run the Rust service directly:
cargo runBy default it listens on 0.0.0.0:5505 and forwards to http://127.0.0.1:8080.
Before starting it locally, create .env from .env.example.
Run tests:
cargo testThe gzip compatibility investigation tests live in tests/cpa_gzip_request_body.rs. The local proxy end-to-end tests live in tests/proxy_forwarding.rs.