feat: support outbound proxy for Chromium sessions (#131)
* feat: support outbound proxy for Chromium sessions Routes WhatsApp Web traffic through an HTTP/HTTPS/SOCKS5 proxy when PROXY_URL is set. Optional PROXY_API_KEY enables auth by passing the key as the basic-auth username (the format API-key proxies expect). No behavior change when unset. Useful for deployments behind egress filters or where outbound WhatsApp traffic must originate from a specific IP. * docs: 📝 rewrite proxy auth part * fix: 🐛 move api key value to passwd * fix: 💄 change var naming * fix: 🎨 change var ref in docs and data passing
This commit is contained in:
parent
7a0cd227fb
commit
132bcf6ee3
5 changed files with 54 additions and 4 deletions
11
.env.example
11
.env.example
|
|
@ -55,4 +55,13 @@ TRUST_PROXY=FALSE
|
|||
|
||||
## CORS ##
|
||||
# OPTIONAL, CORS ALLOWED ORIGINS (comma separated), DEFAULT ALLOWS ALL
|
||||
# ALLOWED_ORIGINS=http://localhost:3000,http://example.com
|
||||
# ALLOWED_ORIGINS=http://localhost:3000,http://example.com
|
||||
|
||||
## Outbound Proxy ##
|
||||
# OPTIONAL, ROUTES CHROMIUM (WHATSAPP WEB) TRAFFIC THROUGH AN OUTBOUND PROXY.
|
||||
# ACCEPTED FORMATS: http://host:port, https://host:port, socks5://host:port
|
||||
# PROXY_URL=http://10.0.0.10:8118
|
||||
# OPTIONAL, PROXY BASIC-AUTH USERNAME
|
||||
# PROXY_USERNAME=
|
||||
# OPTIONAL, PROXY BASIC-AUTH PASSWORD
|
||||
# PROXY_PASSWORD=
|
||||
|
|
@ -163,6 +163,11 @@ By setting the `ENABLE_WEBHOOK` environment to `FALSE` you can disable webhook d
|
|||
|
||||
In order to validate a new WhatsApp Web instance you need to scan the QR code using your mobile phone. Official documentation can be found at (https://faq.whatsapp.com/1079327266110265/?cms_platform=android) page. The service itself delivers the QR code content as a webhook event or you can use the REST endpoints (`/session/qr/:sessionId` or `/session/qr/:sessionId/image` to get the QR code as a png image).
|
||||
|
||||
### Outbound Proxy
|
||||
The Chromium instance that powers each session can be routed through an outbound proxy by setting the `PROXY_URL` environment variable (e.g. `http://10.0.0.10:8118`, `https://...`, or `socks5://...`). When `PROXY_URL` is empty, sessions connect directly with no behavior change.
|
||||
|
||||
If the proxy requires authentication, set `PROXY_USERNAME` and `PROXY_PASSWORD`. When both are defined they are forwarded to Chromium as HTTP Basic auth via puppeteer's `proxyAuthentication`. For API-key vendor proxies, use the vendor-specified username (often `api-key`) and the key itself as the password.
|
||||
|
||||
### WebSocket mode
|
||||
The service can dispatch realtime events through websocket connection. By default, the websocket is not activated, so you need manually set the `ENABLE_WEBSOCKET` environment variable to activate it. The server activates a new websocket instance per each active session. The websocket path is `/ws/:sessionId`, where sessionId is your configured session name. The websocket supports ping/pong scheme to keep the socket running.
|
||||
The below example shows how to receive the events for **test** session.
|
||||
|
|
|
|||
|
|
@ -13,6 +13,16 @@ services:
|
|||
env_file: .env
|
||||
volumes:
|
||||
- ./sessions:/usr/src/app/sessions
|
||||
# Optional: route Chromium (WhatsApp Web) traffic through an outbound proxy.
|
||||
# Set PROXY_URL (and optionally PROXY_USERNAME / PROXY_PASSWORD for HTTP
|
||||
# Basic auth) in .env, or uncomment the block below to point at the
|
||||
# bundled tinyproxy service.
|
||||
# environment:
|
||||
# PROXY_URL: http://tinyproxy:8888
|
||||
# # PROXY_USERNAME: api-key
|
||||
# # PROXY_PASSWORD: your-api-key
|
||||
# depends_on:
|
||||
# - tinyproxy
|
||||
# Optional healthcheck
|
||||
# healthcheck:
|
||||
# test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
|
||||
|
|
@ -20,3 +30,17 @@ services:
|
|||
# timeout: 10s
|
||||
# retries: 3
|
||||
# start_period: 40s
|
||||
|
||||
# Optional: local HTTP proxy for testing the PROXY_URL feature end-to-end.
|
||||
# Uncomment along with the api `environment` / `depends_on` blocks above.
|
||||
# tinyproxy:
|
||||
# image: vimagick/tinyproxy
|
||||
# container_name: wwebjs-tinyproxy
|
||||
# ports:
|
||||
# - "8888:8888"
|
||||
# environment:
|
||||
# ALLOWED_NETWORKS: 0.0.0.0/0
|
||||
# # Uncomment to test the PROXY_USERNAME / PROXY_PASSWORD path.
|
||||
# # BASIC_AUTH_USER: "api-key"
|
||||
# # BASIC_AUTH_PASSWORD: "your-api-key"
|
||||
# restart: unless-stopped
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@ const enableWebSocket = process.env.ENABLE_WEBSOCKET ? (process.env.ENABLE_WEBSO
|
|||
const autoStartSessions = process.env.AUTO_START_SESSIONS ? (process.env.AUTO_START_SESSIONS).toLowerCase() === 'true' : true
|
||||
const basePath = process.env.BASE_PATH || '/'
|
||||
const trustProxy = process.env.TRUST_PROXY ? (process.env.TRUST_PROXY).toLowerCase() === 'true' : false
|
||||
const proxyUrl = process.env.PROXY_URL || null
|
||||
const proxyUsername = process.env.PROXY_USERNAME ?? null
|
||||
const proxyPassword = process.env.PROXY_PASSWORD ?? null
|
||||
|
||||
module.exports = {
|
||||
servicePort,
|
||||
|
|
@ -49,5 +52,8 @@ module.exports = {
|
|||
enableWebSocket,
|
||||
autoStartSessions,
|
||||
basePath,
|
||||
trustProxy
|
||||
trustProxy,
|
||||
proxyUrl,
|
||||
proxyUsername,
|
||||
proxyPassword
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ const { Client, LocalAuth } = require('whatsapp-web.js')
|
|||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const sessions = new Map()
|
||||
const { baseWebhookURL, sessionFolderPath, maxAttachmentSize, setMessagesAsSeen, webVersion, webVersionCacheType, recoverSessions, chromeBin, headless, releaseBrowserLock } = require('./config')
|
||||
const { baseWebhookURL, sessionFolderPath, maxAttachmentSize, setMessagesAsSeen, webVersion, webVersionCacheType, recoverSessions, chromeBin, headless, releaseBrowserLock, proxyUrl, proxyUsername, proxyPassword } = require('./config')
|
||||
const { triggerWebhook, waitForNestedObject, isEventEnabled, sendMessageSeenStatus, sleep, patchWWebLibrary } = require('./utils')
|
||||
const { logger } = require('./logger')
|
||||
const { initWebSocketServer, terminateWebSocketServer, triggerWebSocket } = require('./websocket')
|
||||
|
|
@ -138,12 +138,18 @@ const setupSession = async (sessionId) => {
|
|||
'--use-mock-keychain',
|
||||
'--disable-setuid-sandbox',
|
||||
'--no-sandbox',
|
||||
'--disable-blink-features=AutomationControlled'
|
||||
'--disable-blink-features=AutomationControlled',
|
||||
// Route Chromium outbound traffic through PROXY_URL when configured.
|
||||
...(proxyUrl ? [`--proxy-server=${proxyUrl}`] : [])
|
||||
]
|
||||
},
|
||||
authStrategy: localAuth
|
||||
}
|
||||
|
||||
if (proxyUrl && proxyUsername != null && proxyPassword != null) {
|
||||
clientOptions.proxyAuthentication = { username: proxyUsername, password: proxyPassword }
|
||||
}
|
||||
|
||||
if (webVersion) {
|
||||
clientOptions.webVersion = webVersion
|
||||
switch (webVersionCacheType.toLowerCase()) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue