Minimal HTTP proxy written in Go
494
A minimal HTTP proxy written in Go with two operating modes:
In environments where applications do not have direct internet access, this proxy enables:
*.microsoft.com| Environment Variable | Default Value | Description |
|---|---|---|
PROXY_MODE | (required) | Operation mode: connect or reverse |
LISTEN_ADDR | :8443 (connect) / :9200 (reverse) | Address and port to listen on |
ALLOWED_CLIENTS | (empty = all allowed) | Allowed client IPs/CIDRs |
READ_TIMEOUT | 60s | HTTP server read timeout |
WRITE_TIMEOUT | 60s | HTTP server write timeout |
| Format | Example | Description |
|---|---|---|
:port | :8443 | Listen on all interfaces (IPv4/IPv6) |
port | 8443 | Shorthand for :port (all interfaces) |
ip:port | 127.0.0.1:8443 | Listen on specific IPv4 interface |
[ip6]:port | [::1]:8443 | Listen on specific IPv6 interface |
| Environment Variable | Default Value | Description |
|---|---|---|
ALLOWED_HOSTS | login.microsoftonline.com,graph.microsoft.com,... | Allowed destination hosts |
ALLOWED_PORTS | 443 | Allowed destination ports |
UPSTREAM_PROXY | (empty = direct connection) | Upstream proxy for chaining (host:port) |
DIAL_TIMEOUT | 10s | Connection dial timeout |
TLS_TIMEOUT | 10s | TLS/CONNECT handshake timeout |
| Environment Variable | Default Value | Description |
|---|---|---|
TARGET_URL | (required) | Target URL for forwarding (e.g., https://opensearch.example.com:9200) |
TARGET_HOST | (auto from TARGET_URL) | Host header to set (override if different from URL) |
INSECURE_TLS | false | Skip TLS certificate verification |
CUSTOM_CA | (empty) | Path to custom CA certificate file (e.g., /app/certs/internal-ca.crt) |
MAX_BODY_SIZE | 50MB | Maximum allowed request body size (e.g., 10MB, 1GB) |
ALLOWED_METHODS | (empty = all allowed) | Allowed HTTP methods (e.g., GET,POST,PUT,HEAD) |
TARGET_TIMEOUT | 60s | Request timeout to target |
IDLE_CONN_TIMEOUT | 90s | Idle connection timeout |
DIAL_TIMEOUT | 10s | Connection dial timeout |
TLS_TIMEOUT | 10s | TLS handshake timeout |
Timeout format: Use Go duration format, e.g., 30s, 1m, 2m30s, 1h.
Only allowed hosts can be accessed through the proxy. This setting is ignored in Reverse Proxy mode.
ALLOWED_HOSTS="login.microsoftonline.com,graph.microsoft.com,graph.windows.net,pas.windows.net"
# Allow only specific IPs
ALLOWED_CLIENTS="10.0.0.5,10.0.0.6"
# Allow CIDR ranges
ALLOWED_CLIENTS="10.0.0.0/8,172.16.0.0/12,192.168.0.0/16"
# Allow all (default if not set)
ALLOWED_CLIENTS=""
If your TARGET_URL uses a private or corporate CA, you can mount your CA certificate into the container and point to it:
docker run -d \
-e PROXY_MODE=reverse \
-e TARGET_URL="https://internal-service:9200" \
-e CUSTOM_CA="/certs/internal-ca.crt" \
-v /path/to/my-ca.crt:/certs/internal-ca.crt:ro \
docker.io/invisible/ocp-proxy:latest
# Podman
podman run -d \
-e PROXY_MODE=reverse \
-e TARGET_URL="https://internal-service:9200" \
-e CUSTOM_CA="/certs/internal-ca.crt" \
-v /path/to/my-ca.crt:/certs/internal-ca.crt:ro \
docker.io/invisible/ocp-proxy:latest
Important: Use --network host to preserve real client IPs for ALLOWED_CLIENTS filtering.
Use CONNECT mode for HTTPS tunneling (e.g., Microsoft Entra ID authentication).
Architecture example:
Keycloak (HTTPS) --> CONNECT Proxy (HTTP :8443) --> Entra ID (HTTPS)
ALLOWED_HOSTS=login.microsoftonline.com
docker run -d \
--name keycloak-proxy \
--network host \
--restart unless-stopped \
-e PROXY_MODE=connect \
-e ALLOWED_HOSTS="login.microsoftonline.com,graph.microsoft.com,graph.windows.net,pas.windows.net" \
-e ALLOWED_CLIENTS="10.0.0.0/8,192.168.0.0/16" \
docker.io/invisible/ocp-proxy:latest
podman run -d \
--name keycloak-proxy \
--network host \
--restart unless-stopped \
-e PROXY_MODE=connect \
-e ALLOWED_HOSTS="login.microsoftonline.com,graph.microsoft.com,graph.windows.net,pas.windows.net" \
-e ALLOWED_CLIENTS="10.0.0.0/8,192.168.0.0/16" \
docker.io/invisible/ocp-proxy:latest
When you need to route traffic through multiple proxies (e.g., in multi-tier network environments):
Keycloak (10.0.0.100) --> Proxy 1 (10.0.0.1:8443) --> Proxy 2 (10.0.0.2:8443) --> Entra ID
Proxy 1 (with upstream proxy):
# Docker
docker run -d \
--name keycloak-proxy \
--network host \
--restart unless-stopped \
-e PROXY_MODE=connect \
-e ALLOWED_HOSTS="login.microsoftonline.com,graph.microsoft.com,graph.windows.net,pas.windows.net" \
-e ALLOWED_CLIENTS="10.0.0.100" \
-e UPSTREAM_PROXY="10.0.0.2:8443" \
docker.io/invisible/ocp-proxy:latest
# Podman
podman run -d \
--name keycloak-proxy \
--network host \
--restart unless-stopped \
-e PROXY_MODE=connect \
-e ALLOWED_HOSTS="login.microsoftonline.com,graph.microsoft.com,graph.windows.net,pas.windows.net" \
-e ALLOWED_CLIENTS="10.0.0.100" \
-e UPSTREAM_PROXY="10.0.0.2:8443" \
docker.io/invisible/ocp-proxy:latest
Proxy 2 (direct connection to internet):
# Docker
docker run -d \
--name keycloak-proxy \
--network host \
--restart unless-stopped \
-e PROXY_MODE=connect \
-e ALLOWED_HOSTS="login.microsoftonline.com,graph.microsoft.com,graph.windows.net,pas.windows.net" \
-e ALLOWED_CLIENTS="10.0.0.1" \
docker.io/invisible/ocp-proxy:latest
# Podman
podman run -d \
--name keycloak-proxy \
--network host \
--restart unless-stopped \
-e PROXY_MODE=connect \
-e ALLOWED_HOSTS="login.microsoftonline.com,graph.microsoft.com,graph.windows.net,pas.windows.net" \
-e ALLOWED_CLIENTS="10.0.0.1" \
docker.io/invisible/ocp-proxy:latest
Use reverse proxy mode to forward logs from HTTP to HTTPS endpoints (e.g., OpenSearch, Elasticsearch).
Architecture example:
Application (HTTP) --> Reverse Proxy (HTTP :9200) --> OpenSearch (HTTPS)
TARGET_URL=https://opensearch.example.com:9200
TARGET_HOST=opensearch.example.com
docker run -d \
--name log-proxy \
--network host \
--restart unless-stopped \
-e PROXY_MODE=reverse \
-e TARGET_URL="https://opensearch.example.com:9200" \
-e TARGET_HOST="opensearch.example.com" \
-e ALLOWED_METHODS="POST" \
-e ALLOWED_CLIENTS="10.0.0.0/8,172.16.0.0/12" \
docker.io/invisible/ocp-proxy:latest
podman run -d \
--name log-proxy \
--network host \
--restart unless-stopped \
-e PROXY_MODE=reverse \
-e TARGET_URL="https://opensearch.example.com:9200" \
-e TARGET_HOST="opensearch.example.com" \
-e ALLOWED_METHODS="POST" \
-e ALLOWED_CLIENTS="10.0.0.0/8,172.16.0.0/12" \
docker.io/invisible/ocp-proxy:latest
To chain multiple reverse proxies, set TARGET_URL to point to the next proxy:
App (10.0.0.100) --> Proxy 1 (10.0.0.1:9200) --> Proxy 2 (10.0.0.2:9200) --> OpenSearch
TARGET_URL=http://10.0.0.2:9200
Proxy 1 (in restricted network):
# Docker
docker run -d \
--name log-proxy-1 \
--network host \
--restart unless-stopped \
-e PROXY_MODE=reverse \
-e TARGET_URL="http://10.0.0.2:9200" \
-e ALLOWED_METHODS="POST" \
-e ALLOWED_CLIENTS="10.0.0.100" \
docker.io/invisible/ocp-proxy:latest
# Podman
podman run -d \
--name log-proxy-1 \
--network host \
--restart unless-stopped \
-e PROXY_MODE=reverse \
-e TARGET_URL="http://10.0.0.2:9200" \
-e ALLOWED_METHODS="POST" \
-e ALLOWED_CLIENTS="10.0.0.100" \
docker.io/invisible/ocp-proxy:latest
Proxy 2 (with access to OpenSearch):
# Docker
docker run -d \
--name log-proxy-2 \
--network host \
--restart unless-stopped \
-e PROXY_MODE=reverse \
-e TARGET_URL="https://opensearch.example.com:9200" \
-e TARGET_HOST="opensearch.example.com" \
-e ALLOWED_METHODS="POST" \
-e ALLOWED_CLIENTS="10.0.0.1" \
docker.io/invisible/ocp-proxy:latest
# Podman
podman run -d \
--name log-proxy-2 \
--network host \
--restart unless-stopped \
-e PROXY_MODE=reverse \
-e TARGET_URL="https://opensearch.example.com:9200" \
-e TARGET_HOST="opensearch.example.com" \
-e ALLOWED_METHODS="POST" \
-e ALLOWED_CLIENTS="10.0.0.1" \
docker.io/invisible/ocp-proxy:latest
Configure the client (e.g., Keycloak) to use the proxy:
JAVA_OPTS_APPEND="-Dhttp.proxyHost=keycloak-proxy -Dhttp.proxyPort=8443 -Dhttp.nonProxyHosts=localhost|127.0.0.1|postgres"
| Parameter | Description |
|---|---|
http.proxyHost | Proxy hostname |
http.proxyPort | Proxy port |
http.nonProxyHosts | Hosts to bypass (pipe-separated) |
Important: nonProxyHosts is required to prevent the client from proxying internal connections (PostgreSQL, etc.).
# Test OpenID configuration (should return JSON)
curl -x http://localhost:8443 https://login.microsoftonline.com/common/.well-known/openid-configuration
# Test blocked host (should return 403 Forbidden)
curl -v -x http://localhost:8443 https://google.com
# Test reverse proxy (forward log to OpenSearch)
curl -X POST http://localhost:9200/_bulk \
-H "Content-Type: application/json" \
-d '{"index":{"_index":"logs"}}
{"message":"test log entry","@timestamp":"2024-01-01T00:00:00Z"}'
# Check proxy health (should forward to target and return response)
curl -I http://localhost:9200/
# Docker
docker logs -f keycloak-proxy
docker logs -f log-proxy
# Podman
podman logs -f keycloak-proxy
podman logs -f log-proxy
Content type
Image
Digest
sha256:71fe22544…
Size
2.6 MB
Last updated
8 months ago
docker pull invisible/ocp-proxy