An HTTP reverse proxy that routes requests to backend ports specified in the URL path.
portPxy extracts a port number from the first segment of the request path and proxies the request to that port on a backend host. For example, a request to /8081/api/endpoint is forwarded to backend:8081/api/endpoint.
This solves the problem of dynamically exposing multiple backend ports through a single proxy endpoint, particularly useful in Kubernetes environments where applications create HTTP listeners on various ports at runtime.
Applications like Apache NiFi allow users to configure HTTP listeners on arbitrary ports at runtime (e.g., ListenHTTP processors, webhook receivers). In Kubernetes, these dynamic ports cannot be easily exposed through standard Service or Ingress configurations without constant reconfiguration.
portPxy provides a single ingress endpoint that routes to backend ports based on the URL path:
- External request:
https://app.example.com/8081/webhook - Ingress routes to portPxy on port 8080
- portPxy proxies to
backend:8081/webhook
- Extract port from the first path segment (e.g.,
/8081/path→ port 8081) - Validate port is within the allowed range
- Proxy request to
BACKEND_PROTO://BACKEND_HOST:8081/path - Return backend response to client
The proxy records Prometheus metrics and structured logs for each request.
All settings are configured via environment variables or command-line flags:
| Variable | Flag | Default | Description |
|---|---|---|---|
IP |
-ip |
127.0.0.1 |
Server bind address |
PORT |
-port |
8080 |
Proxy server port |
METRICS_PORT |
-metricsPort |
2112 |
Prometheus metrics port |
DEBUG |
-debug |
false |
Enable debug logging |
BACKEND_HOST |
-backendHost |
httpbin.org |
Target backend hostname |
BACKEND_PROTO |
-backendProto |
https |
Backend protocol (http/https) |
ALLOW_PORT_BEGIN |
-allowRangeBegin |
443 |
Start of allowed port range |
ALLOW_PORT_END |
-allowRangeEnd |
443 |
End of allowed port range |
# Build
go build -o portpxy ./cmd/portpxy.go
# Run with defaults (proxies to httpbin.org:443)
./portpxy
# Run with custom backend
./portpxy -ip=0.0.0.0 -backendHost=localhost -backendProto=http -allowRangeBegin=8080 -allowRangeEnd=8090
# Or use environment variables
IP=0.0.0.0 BACKEND_HOST=localhost BACKEND_PROTO=http ALLOW_PORT_BEGIN=8080 ALLOW_PORT_END=8090 ./portpxy# Run with Docker
docker run --rm -p 8080:8080 -e IP=0.0.0.0 txn2/portpxy:latest
# Custom configuration
docker run --rm -p 8080:8080 \
-e IP=0.0.0.0 \
-e BACKEND_HOST=localhost \
-e BACKEND_PROTO=http \
-e ALLOW_PORT_BEGIN=8080 \
-e ALLOW_PORT_END=8090 \
txn2/portpxy:latestDeploy as a sidecar container alongside your application:
apiVersion: v1
kind: Pod
metadata:
name: app-with-proxy
spec:
containers:
- name: app
image: your-app:latest
# Application creates listeners on ports 8080-8090
- name: portpxy
image: txn2/portpxy:latest
ports:
- containerPort: 8080
name: proxy
- containerPort: 2112
name: metrics
env:
- name: IP
value: "0.0.0.0"
- name: BACKEND_HOST
value: "localhost"
- name: BACKEND_PROTO
value: "http"
- name: ALLOW_PORT_BEGIN
value: "8080"
- name: ALLOW_PORT_END
value: "8090"# Start the proxy with local backend
IP=0.0.0.0 BACKEND_HOST=localhost BACKEND_PROTO=http ALLOW_PORT_BEGIN=8080 ALLOW_PORT_END=8090 ./portpxy
# In another terminal, start a test server on port 8081
python3 -m http.server 8081
# Test proxying
curl http://localhost:8080/8081/
# Test port validation (should return error)
curl http://localhost:8080/9999/
# Check metrics
curl http://localhost:2112/metricsPrometheus metrics are exposed on the metrics port (default 2112):
portpxy_total_requests: Total number of requests processedportpxy_response_time: Request latency distribution
The ALLOW_PORT_BEGIN and ALLOW_PORT_END settings restrict which ports can be proxied. This prevents unauthorized access to arbitrary ports on the backend host. Configure these values to match your application's port range.
go build -o portpxy ./cmd/portpxy.gogoreleaser --skip-publish --rm-dist --skip-validateGITHUB_TOKEN=$GITHUB_TOKEN goreleaser --rm-distMIT