Skip to content

fix: support explicit http proxy protocol#13

Open
TBDevMaster wants to merge 1 commit intoEvolutionAPI:mainfrom
TBDevMaster:proxy-http-fix-testbranch
Open

fix: support explicit http proxy protocol#13
TBDevMaster wants to merge 1 commit intoEvolutionAPI:mainfrom
TBDevMaster:proxy-http-fix-testbranch

Conversation

@TBDevMaster
Copy link
Copy Markdown

@TBDevMaster TBDevMaster commented Apr 5, 2026

Summary

This fixes proxy-based QR pairing for HTTP proxies.

Evolution Go documentation currently describes instance proxy configuration in a way that suggests HTTP proxy support, but the runtime client bootstrap was always creating a SOCKS5 dialer. In practice, this caused QR pairing to hang when using HTTP proxy providers such as NodeMaven on port 8080.

What changed

  • added optional protocol support to proxy configuration
  • added PROXY_PROTOCOL to global config/env
  • replaced hardcoded SOCKS5 bootstrap path with client.SetProxyAddress(...)
  • infer protocol when omitted:
    • socks5 for common SOCKS ports (1080, 2080, 42000-43000)
    • http otherwise
  • exposed normalized protocol in the instance proxy response
  • updated docs/examples to mention protocol

Why

I reproduced the issue with the same proxy in two stacks:

  • older Evolution API + same HTTP proxy => QR returned normally
  • Evolution Go + same HTTP proxy:
    • create => success
    • connect => success
    • qr => hung / timed out

After this patch, local testing with the same NodeMaven HTTP proxy produced:

  • Proxy enabled (http)
  • QR generated successfully

Notes

This keeps SOCKS5 support available, but stops forcing SOCKS5 for proxy configurations that are actually HTTP.

Summary by Sourcery

Add protocol-aware proxy configuration and fix HTTP proxy support for instance connections and QR pairing.

New Features:

  • Support specifying proxy protocol (http, https, socks5) via instance config, API payloads, and PROXY_PROTOCOL environment variable.
  • Expose normalized proxy protocol in instance proxy responses and logs.

Bug Fixes:

  • Resolve hanging QR pairing and connection issues when using HTTP proxies by using a generic proxy address instead of forcing SOCKS5.

Enhancements:

  • Introduce utility functions to normalize proxy protocols and build proxy URLs with credential support.
  • Infer proxy protocol automatically from the configured port when it is not explicitly provided.
  • Ensure instance creation and proxy updates persist normalized proxy configuration.

Documentation:

  • Document PROXY_PROTOCOL in environment variables and configuration guides, including supported protocols and defaulting behavior.
  • Update API instance proxy configuration docs and examples to include the optional protocol field.

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai bot commented Apr 5, 2026

Reviewer's Guide

Adds protocol-aware proxy support (HTTP/HTTPS/SOCKS5) to Evolution Go by normalizing proxy protocol, building generic proxy URLs, wiring configuration/env/instance APIs to carry the protocol field, and updating docs and logging, so QR pairing works behind HTTP proxies instead of assuming SOCKS5 only.

Sequence diagram for updating and applying instance proxy with protocol

sequenceDiagram
  actor Client
  participant InstanceHandler
  participant InstancesService
  participant Utils
  participant InstanceRepository
  participant WhatsmeowService
  participant WhatsmeowClient

  Client->>InstanceHandler: POST /instance/proxy/{id} body SetProxyStruct
  InstanceHandler->>InstancesService: SetProxyFromStruct(id, data)
  InstancesService->>InstancesService: build InstanceProxyConfig from SetProxyStruct
  InstancesService->>InstancesService: SetProxy(id, proxyConfig)
  InstancesService->>Utils: NormalizeProxyProtocol(proxyConfig.Protocol, proxyConfig.Port)
  Utils-->>InstancesService: normalizedProtocol
  InstancesService->>InstancesService: set proxyConfig.Protocol = normalizedProtocol
  InstancesService->>InstanceRepository: UpdateProxy(id, proxyJSON)
  InstanceRepository-->>InstancesService: ok
  InstancesService->>InstancesService: log Proxy configuration updated
  InstancesService->>WhatsmeowService: Reconnect(instance)

  WhatsmeowService->>WhatsmeowService: StartClient(cd)
  WhatsmeowService->>WhatsmeowService: resolve proxyHost, proxyPort, proxyProtocol, proxyUsername, proxyPassword
  WhatsmeowService->>Utils: BuildProxyAddress(proxyProtocol, proxyHost, proxyPort, proxyUsername, proxyPassword)
  Utils-->>WhatsmeowService: proxyAddress or error
  alt proxyAddress built
    WhatsmeowService->>WhatsmeowClient: SetProxyAddress(proxyAddress)
    WhatsmeowClient-->>WhatsmeowService: ok
    WhatsmeowService->>WhatsmeowService: log Proxy enabled (protocol)
  else build or set failed
    WhatsmeowService->>WhatsmeowService: log Proxy error, continuing without proxy
  end
Loading

Class diagram for updated proxy configuration and utilities

classDiagram

class Config {
  +string ProxyHost
  +string ProxyProtocol
  +string ProxyPort
  +string ProxyUsername
  +string ProxyPassword
}

class InstanceProxyConfig {
  +string Protocol
  +string Host
  +string Port
  +string Username
  +string Password
}

class WhatsmeowProxyConfig {
  +string Protocol
  +string Host
  +string Port
  +string Username
  +string Password
}

class SetProxyStruct {
  +string Protocol
  +string Host
  +string Port
  +string Username
  +string Password
}

class CreateStruct {
  +InstanceProxyConfig Proxy
}

class InstancesService {
  +Create(data CreateStruct) Instance
  +SetProxy(id string, proxyConfig InstanceProxyConfig) error
  +SetProxyFromStruct(id string, data SetProxyStruct) error
}

class Utils {
  +NormalizeProxyProtocol(protocol string, port string) string
  +BuildProxyAddress(protocol string, host string, port string, user string, password string) (string, error)
}

class WhatsmeowService {
  +StartClient(cd ClientData) void
  +StartInstance(instanceId string) error
}

Config --> WhatsmeowService : provides proxy settings
Config --> InstancesService : provides default proxy
SetProxyStruct --> InstancesService : input
InstanceProxyConfig <-- CreateStruct : field Proxy
InstanceProxyConfig <-- InstancesService : uses
InstanceProxyConfig <-- WhatsmeowService : uses
WhatsmeowProxyConfig <-- WhatsmeowService : uses
Utils <.. InstancesService : uses NormalizeProxyProtocol
Utils <.. WhatsmeowService : uses NormalizeProxyProtocol
Utils <.. WhatsmeowService : uses BuildProxyAddress
Loading

Flow diagram for NormalizeProxyProtocol behavior

flowchart TD
  A[Input protocol and port] --> B[normalized = lowercased trimmed protocol]
  B --> C{normalized is socks?}
  C -- yes --> D[return socks5]
  C -- no --> E{normalized is http, https or socks5?}
  E -- yes --> F[return normalized]
  E -- no --> G{port is 1080 or 2080?}
  G -- yes --> H[return socks5]
  G -- no --> I[try parse port as integer]
  I --> J{parse ok and 42000 <= port <= 43000?}
  J -- yes --> H
  J -- no --> K[return http]
  D --> L[End]
  F --> L
  H --> L
  K --> L
Loading

File-Level Changes

Change Details Files
Introduce protocol normalization and generic proxy URL builder to support HTTP, HTTPS, and SOCKS5 proxies.
  • Added NormalizeProxyProtocol to normalize/guess proxy protocol from protocol+port with SOCKS5 heuristics and HTTP as default.
  • Added BuildProxyAddress to validate proxy host/port, normalize protocol, construct a url.URL (including optional auth), and return its string form.
  • Kept existing SOCKS5 support but removed hard-coded SOCKS-only behavior in favor of protocol-aware configuration.
pkg/utils/utils.go
Wire proxy protocol through whatsmeow client startup and instance lifecycle, switching from SOCKS5 dialer to SetProxyAddress.
  • Extended ProxyConfig used by whatsmeow service and instance service/DTOs with an optional protocol field in JSON APIs.
  • In StartClient, merged per-instance and global proxy config, including protocol fallback from global config, then built a proxy URL via BuildProxyAddress and passed it to client.SetProxyAddress.
  • Improved logging to include normalized protocol and added error handling for both proxy URL building and SetProxyAddress failures.
  • When bootstrapping instance.Proxy from global config, now construct a full ProxyConfig (including normalized protocol) and marshal it to JSON instead of formatting a fixed HTTP JSON string.
  • Normalize and persist protocol in Create and SetProxy flows so stored proxy configs always contain the normalized protocol.
  • Adjusted SetProxy logging to include the protocol scheme and updated handler responses to return normalized protocol in the API response.
pkg/whatsmeow/service/whatsmeow.go
pkg/instance/service/instance_service.go
pkg/instance/handler/instance_handler.go
Extend configuration and environment variables to carry proxy protocol and update documentation and examples.
  • Added ProxyProtocol field to Config, loaded from new PROXY_PROTOCOL env var, and exposed corresponding constant in config/env.
  • Updated docs to describe generic proxy support (HTTP/HTTPS/SOCKS5), document PROXY_PROTOCOL, and show examples including the protocol field in request/response bodies and .env snippets.
  • Updated the instance proxy API docs to clarify protocol inference behavior and supported values.
pkg/config/config.go
pkg/config/env/env.go
docs/wiki/fundamentos/configuration.md
docs/wiki/guias-api/api-instances.md
docs/wiki/referencia/environment-variables.md
.env.example

Possibly linked issues

  • #[BUG] QR pairing hangs when proxy is enabled: PR adds explicit HTTP proxy support and protocol handling, resolving the hanging QR pairing behavior described in the issue.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • In BuildProxyAddress, you validate against the normalized protocol but emit an error message using the original protocol value; consider either validating against the raw value or using the normalized one in the error message so users get clearer, more consistent feedback (e.g., if they passed SOCKS).
  • There are now two ProxyConfig structs (in pkg/whatsmeow/service and pkg/instance/service) that must stay in sync as new fields like protocol are added; consider extracting a shared type to reduce duplication and the risk of divergence.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `BuildProxyAddress`, you validate against the normalized protocol but emit an error message using the original `protocol` value; consider either validating against the raw value or using the normalized one in the error message so users get clearer, more consistent feedback (e.g., if they passed `SOCKS`).
- There are now two `ProxyConfig` structs (in `pkg/whatsmeow/service` and `pkg/instance/service`) that must stay in sync as new fields like `protocol` are added; consider extracting a shared type to reduce duplication and the risk of divergence.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@TBDevMaster
Copy link
Copy Markdown
Author

I opened a PR with a proposed fix:

#13

What I validated:

  • same HTTP proxy that previously failed in Evolution Go now generates QR successfully
  • local patched test showed Proxy enabled (http) followed by QR generation
  • VPS test also started generating QR with proxy after applying the patch

So this appears to fix the proxy bootstrap issue for HTTP proxies while preserving SOCKS5 support.

@brunohenriquecontente
Copy link
Copy Markdown

Thanks for the quick fix — just dropping in to confirm this is exactly the bug we were seeing with Evolution Go + NodeMaven residential proxy, and that this branch resolves it in our real deployment.

Same root cause, independently reproduced

We hit the identical symptom in our DES environment using NodeMaven HTTP proxy (gate.nodemaven.com:8080, residential IP in Brazil). Logs matched yours to the letter:

Starting websocket connection to Whatsapp
No jid found. Creating new device
Setting whatsapp version from web to 2.3000.1036731287
Proxy enabled                              ← last line, would hang forever

Measured traffic delta on the NodeMaven API (stats endpoint) during a stuck pairing attempt: 0 bytes. So we confirmed independently that the whatsmeow client never actually reached the HTTP proxy — it was trying SOCKS5 on an HTTP endpoint and failing silently. Your source-code analysis (CreateSocks5Proxy / SetSOCKSProxy being called regardless of protocol) lined up perfectly.

Validation of this PR's patch

Instead of writing a parallel fix, I built proxy-http-fix-testbranch (commit 46019728) locally and deployed it to our DES environment (evoapicloud/evolution-go base image, built from your branch with our own tag). Ran end-to-end:

  1. Create instance with HTTP proxy/instance/create accepts protocol-less config, service logs now show Proxy enabled (http) (nice touch, helpful for debugging)
  2. Pair code flowPOST /instance/pair returns a real PairingCode in ~660ms (was hanging indefinitely before). QR code flow also works and emits webhooks correctly.
  3. Full session — scanned pair code on device, PairSuccess webhook arrived, instance transitioned to Connected=true, LoggedIn=true, history sync ran normally.
  4. NodeMaven traffic stats — verified via their API that real tunneled traffic passes through the proxy: web.whatsapp.com 25 req / 368 KB + media-bsb1-1.cdn.whatsapp.net 3 req / 467 KB across the session. Both control and media channels are routed via the HTTP proxy.

Additional notes from our testing

  • Your port-based protocol inference (1080, 2080, 42000-43000 → SOCKS5, else → HTTP) worked transparently for us — we didn't need to set protocol explicitly in the config since NodeMaven uses :8080.
  • The Proxy enabled (http) log addition is super useful for diagnosing which transport was actually selected.
  • I'd suggest adding a similar explicit log for (socks5) so users can tell from logs alone which path was taken, but that's a nit.

Would love to see this merged so we can switch back to evoapicloud/evolution-go:latest in our stack. Happy to help with any additional testing if needed. Thanks again for tracking this down!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants