Environment
- PegaProx: Beta 0.9.14, official Docker image
ghcr.io/pegaprox/pegaprox:0.9.14
- Deployment: Docker Compose; TLS chain: Traefik (TLS termination) → nginx (path routing, adapted from
examples/nginx.conf) → PegaProx
- Behind Reverse Proxy: enabled via Settings → Server (UI toggle);
PEGAPROX_BEHIND_PROXY=true also set
- Result: app binds to
127.0.0.1 with SSL disabled, as expected; nginx shares the container's network namespace (network_mode: "service:pegaprox") and reaches the backends on loopback
- Web UI, SSE, noVNC, node shell and LXC terminal all work correctly — this issue is about log noise / a failing internal operation only
Symptom
With behind-proxy mode active (SSL disabled (handled by reverse proxy) in startup log), the log periodically fills with entries like:
<gevent._socket3.socket at 0x7f76057fdda0 object, fd=34, family=2, type=1, proto=0>: (from ('127.0.0.1', 34302)) Invalid HTTP method: '\x16\x03\x01\x05ð\x01\x00\x05ì\x03\x03...'
<gevent._socket3.socket at 0x7f76046f0f30 object, fd=34, family=2, type=1, proto=0>: (from ('127.0.0.1', 40540)) Expected GET method; Got command='\x16\x03\x01\x05ð...'
The payload is a TLS ClientHello (0x16 0x03 0x01). Decoding it shows:
- SNI =
localhost → the client connects by hostname, not IP
- cipher list matches Python
ssl defaults → the client is PegaProx's own Python code
- source is always
127.0.0.1 → same container
- both the main WSGI server (:5000, "Invalid HTTP method") and the VNC WebSocket server (:5001, "Expected GET method") receive these
In other words: an internal component performs https://localhost:<port> requests against listeners that are in plain-HTTP mode, fails the handshake every time, and both sides log binary noise. The very first entries appear ~1 s after startup, before any external request has been proxied, so at least the startup-time occurrences cannot be caused by request headers (X-Forwarded-Proto) — the https scheme must come from persisted config or a computed self-URL.
Suspected cause
The instance initially ran with built-in TLS enabled (default first boot), then was switched to behind-proxy mode. The internal self-URL used for VNC/SSH console WebSocket callbacks (cf. PEGAPROX_URL, default http://127.0.0.1:5000) appears to remain https://localhost:... — either persisted from the TLS-enabled era or derived from SSL config — and is not switched back to http:// when behind-proxy mode disables SSL.
A secondary candidate is the ACME auto-renewal thread (Started ACME auto-renewal thread appears in the log unconditionally), if it probes the local listener's certificate; however, the observed frequency is higher than a daily renewal check, so the self-URL callbacks fit the evidence better.
Reproduction
- Fresh Docker install, let it boot once with default built-in HTTPS
- Enable Behind Reverse Proxy (Settings → Server), restart
- Watch container logs — TLS ClientHello dumps from
127.0.0.1 appear against :5000 and :5001
Expected behavior
When behind-proxy mode disables SSL, internal self-requests (console WS callbacks, any self-probes) should switch to http://, or the components should read the effective scheme from a single source of truth. Failing that, a one-line warning ("skipping X: SSL disabled") would be far preferable to repeated binary dumps.
Workaround being verified
Explicitly setting PEGAPROX_URL=http://127.0.0.1:5000 in the container environment (will report back whether this silences the callbacks).
Related observation (Docker + behind-proxy UX)
PEGAPROX_BEHIND_PROXY=true alone switches the backend (bind 127.0.0.1, SSL off) but the frontend kept building console WebSocket URLs on page port + 1 (e.g. wss://host:444/...) until the UI toggle in Settings → Server was flipped — after which console WS correctly went through 443 per examples/nginx.conf. If intentional, a note on the Reverse Proxy docs page that the UI toggle (not only the env var) is required would save Docker users some debugging; PEGAPROX_URL is also worth mentioning on that page.
Happy to provide full logs, compose files, or run a patched build to verify a fix.
Environment
ghcr.io/pegaprox/pegaprox:0.9.14examples/nginx.conf) → PegaProxPEGAPROX_BEHIND_PROXY=truealso set127.0.0.1with SSL disabled, as expected; nginx shares the container's network namespace (network_mode: "service:pegaprox") and reaches the backends on loopbackSymptom
With behind-proxy mode active (
SSL disabled (handled by reverse proxy)in startup log), the log periodically fills with entries like:The payload is a TLS ClientHello (
0x16 0x03 0x01). Decoding it shows:localhost→ the client connects by hostname, not IPssldefaults → the client is PegaProx's own Python code127.0.0.1→ same containerIn other words: an internal component performs
https://localhost:<port>requests against listeners that are in plain-HTTP mode, fails the handshake every time, and both sides log binary noise. The very first entries appear ~1 s after startup, before any external request has been proxied, so at least the startup-time occurrences cannot be caused by request headers (X-Forwarded-Proto) — thehttpsscheme must come from persisted config or a computed self-URL.Suspected cause
The instance initially ran with built-in TLS enabled (default first boot), then was switched to behind-proxy mode. The internal self-URL used for VNC/SSH console WebSocket callbacks (cf.
PEGAPROX_URL, defaulthttp://127.0.0.1:5000) appears to remainhttps://localhost:...— either persisted from the TLS-enabled era or derived from SSL config — and is not switched back tohttp://when behind-proxy mode disables SSL.A secondary candidate is the ACME auto-renewal thread (
Started ACME auto-renewal threadappears in the log unconditionally), if it probes the local listener's certificate; however, the observed frequency is higher than a daily renewal check, so the self-URL callbacks fit the evidence better.Reproduction
127.0.0.1appear against :5000 and :5001Expected behavior
When behind-proxy mode disables SSL, internal self-requests (console WS callbacks, any self-probes) should switch to
http://, or the components should read the effective scheme from a single source of truth. Failing that, a one-line warning ("skipping X: SSL disabled") would be far preferable to repeated binary dumps.Workaround being verified
Explicitly setting
PEGAPROX_URL=http://127.0.0.1:5000in the container environment (will report back whether this silences the callbacks).Related observation (Docker + behind-proxy UX)
PEGAPROX_BEHIND_PROXY=truealone switches the backend (bind 127.0.0.1, SSL off) but the frontend kept building console WebSocket URLs onpage port + 1(e.g.wss://host:444/...) until the UI toggle in Settings → Server was flipped — after which console WS correctly went through 443 perexamples/nginx.conf. If intentional, a note on the Reverse Proxy docs page that the UI toggle (not only the env var) is required would save Docker users some debugging;PEGAPROX_URLis also worth mentioning on that page.Happy to provide full logs, compose files, or run a patched build to verify a fix.