feat(gateway): add scoped proxy egress deployment
This commit is contained in:
@@ -2,6 +2,9 @@
|
||||
LX_DB_PASSWORD=replace-with-strong-database-password
|
||||
LX_JWT_SECRET=replace-with-at-least-32-random-characters
|
||||
LX_WEB_PORT=8088
|
||||
DEBIAN_MIRROR=https://deb.debian.org/debian
|
||||
DEBIAN_SECURITY_MIRROR=https://deb.debian.org/debian-security
|
||||
FFMPEG_BINARIES_URL=https://github.com/eugeneware/ffmpeg-static/releases/download
|
||||
|
||||
# DeepSeek Anthropic-compatible API
|
||||
DEEPSEEK_API_KEY=replace-with-rotated-deepseek-key
|
||||
@@ -20,6 +23,8 @@ TELEGRAM_WEBHOOK_SECRET=replace-with-random-webhook-secret
|
||||
WHATSAPP_GATEWAY_TOKEN=replace-with-at-least-32-random-characters
|
||||
WHATSAPP_WEBHOOK_SECRET=replace-with-another-32-random-secret
|
||||
WHATSAPP_LOG_LEVEL=info
|
||||
# 可选。只影响 WhatsApp 网关出站,不设置系统或平台全局代理。
|
||||
WHATSAPP_DEFAULT_PROXY_URL=
|
||||
|
||||
PUBLIC_WEBHOOK_BASE_URL=http://host.docker.internal:8088
|
||||
APP_PUBLIC_URL=http://127.0.0.1:8088
|
||||
|
||||
@@ -28,6 +28,7 @@ storage/
|
||||
*.sqlite3
|
||||
*.dump
|
||||
*.sql
|
||||
!telegram-gateway/docker/scripts/init-db.sql
|
||||
*.rdb
|
||||
*.binlog
|
||||
|
||||
|
||||
@@ -2,6 +2,20 @@
|
||||
|
||||
本项目遵循语义化版本。早期版本由经过脱敏的本地源码快照恢复,因此使用带日期的 `snapshot-*` 标签;自 `v1.0.0` 起按正式发布流程维护。
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### 新增
|
||||
|
||||
- Telegram Gateway 支持环境级默认 SOCKS5/HTTP/MTProto 代理,账号专属绑定仍具有更高优先级。
|
||||
- WhatsApp Gateway 支持环境级默认 HTTP/HTTPS 代理,账号专属代理仍可覆盖默认值。
|
||||
- 默认代理仅作用于两个消息网关,不改变平台、邮箱、数据库或 Docker 的全局网络出口。
|
||||
- Docker 构建支持可配置的 Debian 与 FFmpeg 下载镜像,适配受限网络环境。
|
||||
|
||||
### 修复
|
||||
|
||||
- 将 Telegram Gateway 首次启动所需的 PostgreSQL 初始化脚本纳入版本控制,避免空数据库因挂载目录而启动失败。
|
||||
- Telegram Gateway 本机调试端口改为 `127.0.0.1:3010`,避免与 Gitea 的 `3000` 端口冲突并阻止公网直连管理接口。
|
||||
|
||||
## [1.1.0] - 2026-08-01
|
||||
|
||||
### 新增
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
FROM node:20-alpine AS web-build
|
||||
ARG FFMPEG_BINARIES_URL=https://github.com/eugeneware/ffmpeg-static/releases/download
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
RUN npm ci
|
||||
|
||||
@@ -19,10 +19,14 @@ services:
|
||||
whatsapp-gateway:
|
||||
build:
|
||||
context: ./whatsapp-gateway
|
||||
args:
|
||||
DEBIAN_MIRROR: ${DEBIAN_MIRROR:-https://deb.debian.org/debian}
|
||||
DEBIAN_SECURITY_MIRROR: ${DEBIAN_SECURITY_MIRROR:-https://deb.debian.org/debian-security}
|
||||
environment:
|
||||
PORT: 3200
|
||||
DATA_DIR: /data
|
||||
WHATSAPP_GATEWAY_TOKEN: ${WHATSAPP_GATEWAY_TOKEN:?WHATSAPP_GATEWAY_TOKEN is required}
|
||||
WHATSAPP_DEFAULT_PROXY_URL: ${WHATSAPP_DEFAULT_PROXY_URL:-}
|
||||
LOG_LEVEL: ${WHATSAPP_LOG_LEVEL:-info}
|
||||
volumes:
|
||||
- lingxi_whatsapp_data:/data
|
||||
@@ -89,6 +93,8 @@ services:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
args:
|
||||
FFMPEG_BINARIES_URL: ${FFMPEG_BINARIES_URL:-https://github.com/eugeneware/ffmpeg-static/releases/download}
|
||||
ports:
|
||||
- "${LX_WEB_PORT:-8088}:80"
|
||||
depends_on:
|
||||
|
||||
@@ -37,6 +37,24 @@ docker compose logs --tail=100 api whatsapp-gateway web
|
||||
|
||||
平台的 `TELEGRAM_GATEWAY_URL` 指向网关 `/api` 地址。生产环境应通过私有网络连接,不把 Gateway 管理接口直接暴露公网。详细配置见 [Telegram Gateway 接入指南](TELEGRAM-GATEWAY.md)。
|
||||
|
||||
### 2.1 仅消息网关使用出站代理
|
||||
|
||||
生产环境可以创建一个不映射宿主机端口的专用 Docker 网络和 V2Ray/Xray 容器,并只将 Telegram、WhatsApp 网关接入该网络。不要设置 Docker Daemon、宿主机或平台 API 的全局 `HTTP_PROXY`/`HTTPS_PROXY`。
|
||||
|
||||
```env
|
||||
# Telegram Gateway
|
||||
TG_DEFAULT_PROXY_TYPE=socks5
|
||||
TG_DEFAULT_PROXY_HOST=lingxi-egress
|
||||
TG_DEFAULT_PROXY_PORT=10808
|
||||
|
||||
# 平台 WhatsApp Gateway
|
||||
WHATSAPP_DEFAULT_PROXY_URL=http://lingxi-egress:10809
|
||||
```
|
||||
|
||||
账号级代理优先于上述默认代理。代理容器应使用 `internal/external Docker network + no host ports` 的方式隔离;配置文件和认证信息仅保存在服务器受限目录,不进入 Git。上线前至少验证 Telegram API 与 WhatsApp Web 的 HTTPS 连接,并确认 API、数据库、邮箱和 AI 服务未配置全局代理变量。
|
||||
|
||||
若部署网络无法访问 Debian 官方源或 FFmpeg GitHub Release,可通过 `.env` 的 `DEBIAN_MIRROR`、`DEBIAN_SECURITY_MIRROR` 和 `FFMPEG_BINARIES_URL` 指定构建镜像;这些变量只影响镜像构建,不改变运行时出口。
|
||||
|
||||
## 3. 生产入口
|
||||
|
||||
在 Compose 外层部署 Caddy、Nginx 或云负载均衡:
|
||||
@@ -49,6 +67,8 @@ docker compose logs --tail=100 api whatsapp-gateway web
|
||||
|
||||
将 `APP_PUBLIC_URL` 和 `PUBLIC_WEBHOOK_BASE_URL` 改为正式 HTTPS 地址,随后重建 API。
|
||||
|
||||
当前生产拓扑使用 Caddy 与 NPS 时,应在 NPS HTTP Host 中将域名指向平台内网 `8088`,Caddy 只反向代理到 NPS 的本机 HTTP 入口。修改前分别备份 NPS Host 配置和 Caddyfile,验证配置后再重启 NPS、平滑重载 Caddy。
|
||||
|
||||
## 4. 更新
|
||||
|
||||
```bash
|
||||
|
||||
@@ -18,6 +18,7 @@ Copy-Item telegram-gateway/.env.example telegram-gateway/.env
|
||||
- `JWT_SECRET`、`ADMIN_API_KEY`:分别生成强随机值,不得复用。
|
||||
- `DB_PASSWORD`:生产数据库强密码。
|
||||
- `CORS_ORIGINS`:仅填写受信任的管理入口;平台服务端调用不依赖浏览器跨域。
|
||||
- `TG_DEFAULT_PROXY_*`:可选的默认 TDLib 代理;账号绑定的专属代理优先。
|
||||
|
||||
生产环境不要使用示例中的 `postgres` 密码。`.env` 不得提交 Git。
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
# Application
|
||||
NODE_ENV=development
|
||||
# Optional image build mirrors for networks where deb.debian.org is unavailable.
|
||||
DEBIAN_MIRROR=https://deb.debian.org/debian
|
||||
DEBIAN_SECURITY_MIRROR=https://deb.debian.org/debian-security
|
||||
PORT=3000
|
||||
APP_NAME=TelegramUserGateway
|
||||
CORS_ORIGINS=
|
||||
@@ -29,6 +32,14 @@ TDLIB_PATH=/usr/local/lib/libtdjson.so
|
||||
TG_API_ID=0
|
||||
TG_API_HASH=your_api_hash_here
|
||||
|
||||
# 可选默认代理。账号未绑定专属代理时使用;只影响 Telegram TDLib 出站。
|
||||
TG_DEFAULT_PROXY_TYPE=
|
||||
TG_DEFAULT_PROXY_HOST=
|
||||
TG_DEFAULT_PROXY_PORT=
|
||||
TG_DEFAULT_PROXY_USERNAME=
|
||||
TG_DEFAULT_PROXY_PASSWORD=
|
||||
TG_DEFAULT_PROXY_SECRET=
|
||||
|
||||
# Rate Limiting
|
||||
RATE_LIMIT_DEFAULT_TTL=60000
|
||||
RATE_LIMIT_DEFAULT_LIMIT=30
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
FROM node:20-bookworm-slim AS builder
|
||||
|
||||
ARG DEBIAN_MIRROR=https://deb.debian.org/debian
|
||||
ARG DEBIAN_SECURITY_MIRROR=https://deb.debian.org/debian-security
|
||||
RUN sed -i "s|http://deb.debian.org/debian-security|${DEBIAN_SECURITY_MIRROR}|g; s|http://deb.debian.org/debian|${DEBIAN_MIRROR}|g" /etc/apt/sources.list.d/debian.sources
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends g++ make python3 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
@@ -22,6 +25,9 @@ RUN npm prune --omit=dev
|
||||
|
||||
FROM node:20-bookworm-slim
|
||||
|
||||
ARG DEBIAN_MIRROR=https://deb.debian.org/debian
|
||||
ARG DEBIAN_SECURITY_MIRROR=https://deb.debian.org/debian-security
|
||||
RUN sed -i "s|http://deb.debian.org/debian-security|${DEBIAN_SECURITY_MIRROR}|g; s|http://deb.debian.org/debian|${DEBIAN_MIRROR}|g" /etc/apt/sources.list.d/debian.sources
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends tini ca-certificates \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
@@ -30,9 +30,12 @@ services:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: docker/Dockerfile
|
||||
args:
|
||||
DEBIAN_MIRROR: ${DEBIAN_MIRROR:-https://deb.debian.org/debian}
|
||||
DEBIAN_SECURITY_MIRROR: ${DEBIAN_SECURITY_MIRROR:-https://deb.debian.org/debian-security}
|
||||
container_name: tgw-app
|
||||
ports:
|
||||
- '3000:3000'
|
||||
- '127.0.0.1:3010:3000'
|
||||
env_file:
|
||||
- ../.env
|
||||
environment:
|
||||
@@ -52,6 +55,12 @@ services:
|
||||
TDLIB_PATH: /app/node_modules/@prebuilt-tdlib/linux-x64-glibc/libtdjson.so
|
||||
TG_API_ID: ${TG_API_ID}
|
||||
TG_API_HASH: ${TG_API_HASH}
|
||||
TG_DEFAULT_PROXY_TYPE: ${TG_DEFAULT_PROXY_TYPE:-}
|
||||
TG_DEFAULT_PROXY_HOST: ${TG_DEFAULT_PROXY_HOST:-}
|
||||
TG_DEFAULT_PROXY_PORT: ${TG_DEFAULT_PROXY_PORT:-}
|
||||
TG_DEFAULT_PROXY_USERNAME: ${TG_DEFAULT_PROXY_USERNAME:-}
|
||||
TG_DEFAULT_PROXY_PASSWORD: ${TG_DEFAULT_PROXY_PASSWORD:-}
|
||||
TG_DEFAULT_PROXY_SECRET: ${TG_DEFAULT_PROXY_SECRET:-}
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
-- Telegram User Gateway - Database Initialization
|
||||
-- This script runs on first PostgreSQL startup
|
||||
|
||||
-- Enable UUID extension
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||
|
||||
-- Create indexes will be handled by TypeORM synchronize in dev
|
||||
-- or by migrations in production
|
||||
@@ -171,7 +171,7 @@ export class TgAccountsService implements OnModuleInit {
|
||||
const binding = await this.bindingRepo.findOne({
|
||||
where: { accountId, isActive: true },
|
||||
});
|
||||
if (!binding) return undefined;
|
||||
if (!binding) return this.getDefaultProxy();
|
||||
|
||||
const proxy = await this.proxyRepo
|
||||
.createQueryBuilder('proxy')
|
||||
@@ -179,7 +179,7 @@ export class TgAccountsService implements OnModuleInit {
|
||||
.where('proxy.id = :id', { id: binding.proxyId })
|
||||
.andWhere('proxy.isActive = :isActive', { isActive: true })
|
||||
.getOne();
|
||||
if (!proxy) return undefined;
|
||||
if (!proxy) return this.getDefaultProxy();
|
||||
|
||||
return {
|
||||
type: proxy.type,
|
||||
@@ -190,4 +190,27 @@ export class TgAccountsService implements OnModuleInit {
|
||||
secret: proxy.secret,
|
||||
};
|
||||
}
|
||||
|
||||
private getDefaultProxy() {
|
||||
const host = String(process.env.TG_DEFAULT_PROXY_HOST || '').trim();
|
||||
const port = Number(process.env.TG_DEFAULT_PROXY_PORT || 0);
|
||||
if (!host || !Number.isInteger(port) || port < 1 || port > 65535) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const type = String(process.env.TG_DEFAULT_PROXY_TYPE || 'socks5').toLowerCase();
|
||||
if (!['socks5', 'http', 'mtproto'].includes(type)) {
|
||||
this.logger.warn(`Ignoring unsupported TG_DEFAULT_PROXY_TYPE: ${type}`);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
type,
|
||||
host,
|
||||
port,
|
||||
username: process.env.TG_DEFAULT_PROXY_USERNAME || '',
|
||||
password: process.env.TG_DEFAULT_PROXY_PASSWORD || '',
|
||||
secret: process.env.TG_DEFAULT_PROXY_SECRET || '',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
FROM node:20-bookworm-slim
|
||||
|
||||
ARG DEBIAN_MIRROR=https://deb.debian.org/debian
|
||||
ARG DEBIAN_SECURITY_MIRROR=https://deb.debian.org/debian-security
|
||||
RUN sed -i "s|http://deb.debian.org/debian-security|${DEBIAN_SECURITY_MIRROR}|g; s|http://deb.debian.org/debian|${DEBIAN_MIRROR}|g" /etc/apt/sources.list.d/debian.sources
|
||||
|
||||
ENV NODE_ENV=production
|
||||
WORKDIR /app
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ const accountsFile = path.join(dataDir, 'accounts.json')
|
||||
const webhookDeliveriesFile = path.join(dataDir, 'webhook-deliveries.json')
|
||||
const outboundJobsFile = path.join(dataDir, 'outbound-jobs.json')
|
||||
const gatewayToken = String(process.env.WHATSAPP_GATEWAY_TOKEN || '')
|
||||
const defaultProxyUrl = String(process.env.WHATSAPP_DEFAULT_PROXY_URL || '').trim()
|
||||
const maxMessagesPerChat = Math.max(2_000, Number(process.env.MAX_MESSAGES_PER_CHAT || 20_000))
|
||||
const log = pino({ level: process.env.LOG_LEVEL || 'info' })
|
||||
|
||||
@@ -90,7 +91,7 @@ function accountWebhookSecret(account) {
|
||||
}
|
||||
|
||||
function accountProxyUrl(account) {
|
||||
return decryptCredential(account?.proxyUrlEncrypted || '')
|
||||
return decryptCredential(account?.proxyUrlEncrypted || '') || defaultProxyUrl
|
||||
}
|
||||
|
||||
function jsonSafe(value) {
|
||||
|
||||
Reference in New Issue
Block a user