← 返回列表

电报大群推荐 极简运维:使用 Go 语言开发一个免配置、单文件运行的 Telegram 群组消息转发镜像

分类:Telegram群组发布于:2026-08-19

telegram搜

在 Telegram 社群运营中,将一个群组的消息同步到另一个群组,看似只是简单的“收到后再发送”,实际却涉及机器人权限、消息类型兼容、更新游标、限流重试和进程守护等问题。

如果为这类小工具引入数据库、配置中心和大型机器人框架,部署成本往往高于功能本身。更适合个人站长和轻量运维团队的方案,是使用 Go 标准库构建一个无第三方依赖、无配置文件、可编译为单个二进制文件的 Telegram 消息转发镜像。

🧭 先明确“免配置”的边界

电报大群推荐 本文所说的免配置,并不是把 Bot Token 和群组 ID 硬编码进源码,而是不依赖 YAML、JSON、数据库或外部服务。程序只从环境变量读取三个运行参数,编译后即可独立运行。

电报大群推荐 这种方式既保留了单文件部署的便利,也避免敏感 Token 出现在 Git 仓库中。最终程序只有一个可执行文件,非常适合放入轻量云服务器、NAS、软路由或容器中运行。

TG_BOT_TOKEN=机器人令牌
SRC_CHAT_ID=来源群组ID
DST_CHAT_ID=目标群组ID

🔐 创建机器人并配置群组权限

首先在 Telegram 中打开 @BotFather,执行 /newbot 创建机器人并保存 Token。Token 等同于机器人密码,不应发送到群聊、截图或提交到公开代码仓库。

随后将机器人同时加入来源群和目标群。来源群需要允许机器人读取消息,目标群需要授予发送消息和发送媒体的权限。

关闭群组隐私模式

Telegram 机器人默认启用 Privacy Mode,此时它通常只能看到命令、回复和与自己相关的消息。要镜像普通群消息,需要在 BotFather 中打开 /setprivacy,选择机器人后设置为 Disable。

修改隐私模式后,建议将机器人移出来源群再重新加入,确保权限状态及时刷新。若群组安全策略不允许关闭隐私模式,也可以将机器人提升为管理员。

获取来源群与目标群 ID

将机器人加入群组后,在群内发送一条测试消息,然后访问 Bot API 的 getUpdates 接口。返回结果中的 message.chat.id 就是群组 ID,超级群通常以 -100 开头。

https://api.telegram.org/bot<BOT_TOKEN>/getUpdates

如果接口返回空数组,先确认机器人已经收到新消息,并检查是否有其他程序正在通过 Long Polling 或 Webhook 消费更新。同一个机器人不应同时运行两套 getUpdates 消费进程。

⚙️ 使用 Go 标准库实现消息镜像

核心流程分为两步:通过 getUpdates 长轮询接收来源群消息,再调用 copyMessage 将消息复制到目标群。copyMessage 可覆盖文本、图片、视频、文件、语音和贴纸等常用类型,而且不会显示“转发自”标记。

下面的程序只使用 Go 标准库,源码可以保存为 main.go。它会校验环境变量、维护 update_id 游标,并在 Telegram 返回限流信息时自动等待。

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"strconv"
	"time"
)

type Update struct {
	UpdateID int `json:"update_id"`
	Message  *struct {
		MessageID int `json:"message_id"`
		Chat      struct {
			ID int64 `json:"id"`
		} `json:"chat"`
	} `json:"message"`
}

type UpdatesResponse struct {
	OK     bool     `json:"ok"`
	Result []Update `json:"result"`
}

type APIResponse struct {
	OK          bool   `json:"ok"`
	Description string `json:"description"`
	Parameters  struct {
		RetryAfter int `json:"retry_after"`
	} `json:"parameters"`
}

var client = &http.Client{Timeout: 70 * time.Second}

func envInt64(name string) int64 {
	value := os.Getenv(name)
	id, err := strconv.ParseInt(value, 10, 64)
	if err != nil {
		log.Fatalf("%s 必须是有效的群组 ID", name)
	}
	return id
}

func postJSON(url string, payload any, result any) error {
	body, err := json.Marshal(payload)
	if err != nil {
		return err
	}

	resp, err := client.Post(url, "application/json", bytes.NewReader(body))
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	data, err := io.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	if err := json.Unmarshal(data, result); err != nil {
		return fmt.Errorf("无法解析 Telegram 响应: %w", err)
	}
	return nil
}

func main() {
	token := os.Getenv("TG_BOT_TOKEN")
	if token == "" {
		log.Fatal("缺少 TG_BOT_TOKEN")
	}

	sourceID := envInt64("SRC_CHAT_ID")
	targetID := envInt64("DST_CHAT_ID")
	baseURL := "https://api.telegram.org/bot" + token
	offset := 0

	log.Printf("镜像已启动: %d -> %d", sourceID, targetID)

	for {
		var updates UpdatesResponse
		err := postJSON(baseURL+"/getUpdates", map[string]any{
			"offset":  offset,
			"timeout": 50,
			"allowed_updates": []string{"message"},
		}, &updates)

		if err != nil || !updates.OK {
			log.Printf("拉取更新失败: %v", err)
			time.Sleep(3 * time.Second)
			continue
		}

		for _, update := range updates.Result {
			offset = update.UpdateID + 1

			if update.Message == nil ||
				update.Message.Chat.ID != sourceID {
				continue
			}

			for {
				var result APIResponse
				err = postJSON(baseURL+"/copyMessage", map[string]any{
					"chat_id":      targetID,
					"from_chat_id": sourceID,
					"message_id":   update.Message.MessageID,
				}, &result)

				if err == nil && result.OK {
					break
				}
				if result.Parameters.RetryAfter > 0 {
					time.Sleep(time.Duration(result.Parameters.RetryAfter) * time.Second)
					continue
				}

				log.Printf("消息 %d 复制失败: %s",
					update.Message.MessageID, result.Description)
				break
			}
		}
	}
}

程序只处理 sourceID 对应的消息,因此目标群中的机器人消息不会被再次转发,也不会形成死循环。offset 每处理一个更新便向前推进,可避免同一运行周期内重复消费。

这里没有将 Token 拼进日志,也没有把完整 API 响应长期保存到磁盘。对于包含用户资料和聊天内容的生产环境,这种最小化日志原则更符合隐私与安全要求。

电报精准找群黑科技提示:

由于 Telegram 官方搜索对中文支持极差,很多优质的推广、技术和资源群组隐藏极深。如果你正在寻找相关的活跃社群,强烈推荐使用本站首页的 【TTSO - Telegram 智能搜索 Bot】。作为目前最好用的电报综合搜索导航,只需输入关键词,即可秒级触达数十万个精选 TG 中文群组、资源频道。一键直达,帮你节省 90% 的找群时间!

电报大群推荐 🚀 编译并单文件运行

电报大群推荐 本地安装 Go 1.22 或更新版本后,在源码目录执行编译命令。由于程序没有第三方模块,整个过程不需要 go.mod,也不需要下载 Telegram SDK。

CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o tg-mirror main.go

编译完成后得到 tg-mirror 单文件。部署到 Linux 服务器时,只需传输这个二进制文件并注入三个环境变量,不需要安装 Go 运行时。

export TG_BOT_TOKEN="123456:ABCDEF"
export SRC_CHAT_ID="-1001111111111"
export DST_CHAT_ID="-1002222222222"

./tg-mirror

交叉编译到 Linux

如果开发电脑是 Windows 或 macOS,可以直接交叉编译 Linux 版本。部署前应使用 uname -m 确认服务器是 amd64 还是 arm64 架构。

CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -ldflags="-s -w" -o tg-mirror main.go

🛡️ 用 systemd 保持长期运行

直接在 SSH 终端启动程序,断开连接后进程可能退出。生产环境建议交给 systemd 管理,以获得开机启动、异常重启和统一日志能力。

先将二进制文件放到 /opt/tg-mirror/,再创建服务单元。Environment 中含有敏感 Token,因此服务文件应限制为 root 可读。

[Unit]
Description=Telegram Group Message Mirror
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
WorkingDirectory=/opt/tg-mirror
ExecStart=/opt/tg-mirror/tg-mirror
Environment="TG_BOT_TOKEN=123456:ABCDEF"
Environment="SRC_CHAT_ID=-1001111111111"
Environment="DST_CHAT_ID=-1002222222222"
Restart=always
RestartSec=5
NoNewPrivileges=true

[Install]
WantedBy=multi-user.target
sudo chmod 600 /etc/systemd/system/tg-mirror.service
sudo systemctl daemon-reload
sudo systemctl enable --now tg-mirror
sudo journalctl -u tg-mirror -f

上线后应分别测试纯文本、图片、视频、文件和回复消息,并检查目标群权限。若需要零丢失、审计记录或多实例高可用,则应额外引入持久化队列,这已经超出极简单机镜像的适用范围。

🔍 必须了解的 Telegram 限制

copyMessage 无法复制部分服务消息、付费媒体及受保护内容。来源群如果开启禁止保存内容,机器人也可能无法完成复制,这属于平台限制而不是 Go 程序故障。

媒体组会以多条更新到达,逐条 copyMessage 虽能复制内容,但不一定保持原始相册形态。需要完整保留相册时,应按 media_group_id 短暂聚合,再调用 sendMediaGroup。

此外,copyMessage 不展示原作者来源,适合内容镜像;如果运营规则要求保留出处,应改用 forwardMessage。涉及用户内容时,还应提前说明同步范围,并遵守当地隐私法规和 Telegram 服务条款。

❓ 常见问题解答(FAQ)

机器人在线,但为什么收不到普通群消息?

电报大群推荐 最常见原因是 Privacy Mode 仍处于启用状态。请通过 BotFather 关闭隐私模式,重新添加机器人,并确认没有 Webhook 或另一进程正在消费更新。

为什么目标群返回 Forbidden 错误?

这通常表示机器人未加入目标群、已被封禁,或者没有发送对应媒体类型的权限。将机器人设为管理员后重新测试,并核对 DST_CHAT_ID 是否正确。

程序重启会不会重复转发消息?

正常推进过 offset 的更新会被 Telegram 确认,不会持续返回。极端情况下,进程可能在复制成功但确认下一批更新前退出;对严格去重有要求时,应持久化 update_id 或消息 ID。

可以同时镜像多个群组吗?

可以,但应将来源与目标关系改成映射表,并对不同目标分别处理失败和限流。群组数量较多时,建议加入任务队列和并发上限,避免触发 Telegram API 频率限制。

这种方案适合哪些场景?

它适合公告同步、内部备份、社群迁移和小规模内容分发,优势是部署简单、资源占用低、故障面小。对于金融交易、合规归档或不能容忍重复与丢失的业务,应使用数据库、幂等键和可观测性更完整的架构。

telegram搜
Telegram搜索入口客服ID@TTSO联系