Update Mihomo configuration and documentation for clarity
- Revised comments in `config.example.yaml` to enhance understanding of Mihomo integration, including environment variable usage and Docker Compose setup. - Updated `docker-compose.yml` comments to clarify the relationship between the gateway and Mihomo service. - Enhanced `GATEWAY_RUN.md` to provide clearer instructions on configuring Mihomo parameters and their usage in the gateway.
This commit is contained in:
+2
-5
@@ -1,14 +1,11 @@
|
||||
# Пример для docker compose: без whitelist (только для локальной проверки).
|
||||
# На Linux в docker-compose.yml задано extra_hosts host.docker.internal:host-gateway.
|
||||
# Без Mihomo: как ниже. С Mihomo в той же сети — см. config.example.yaml и docs/GATEWAY_RUN.md.
|
||||
listen: ":8080"
|
||||
allow_all: true
|
||||
whitelist_cidrs: []
|
||||
trusted_proxies: []
|
||||
# UI отдаётся с того же порта, что и API (образ шлюза) — отдельный CORS для панели не нужен.
|
||||
# UI отдаётся с тем же портом, что и API (образ шлюза) — отдельный CORS для панели не нужен.
|
||||
servers:
|
||||
- alias: main_srv
|
||||
base_url: http://host.docker.internal:9091
|
||||
# Раскомментируйте при настройке Mihomo и общей сети с контейнером mihomo:
|
||||
# mihomo_base_url: http://mihomo:9090
|
||||
# или: mihomo_base_url_env: MIHOMO_CONTROLLER_URL
|
||||
# mihomo_authorization_env: TELEMT_MIHOMO_AUTH
|
||||
|
||||
+4
-35
@@ -52,41 +52,10 @@ servers:
|
||||
base_url: http://127.0.0.1:9091
|
||||
path_prefix: /v1
|
||||
# authorization_env: TELEMT_API_AUTH
|
||||
#
|
||||
# --- Mihomo (Clash Meta), раздел «Mihomo» в панели (/servers/{alias}/mihomo) ---
|
||||
# Клиент: GET /api/{alias}/mihomo/… и WebSocket — шлюз проксирует на external-controller с Bearer.
|
||||
#
|
||||
# Типичный compose для самого Mihomo (отдельный файл или сервис рядом с gateway):
|
||||
# mihomo:
|
||||
# build: ./mihomo
|
||||
# container_name: mihomo
|
||||
# environment:
|
||||
# - SUB_URL=https://example.com/sub
|
||||
# - CLASH_SECRET=your-secret-here
|
||||
# - UPDATE_INTERVAL=86400
|
||||
# # ports: # публиковать 9090 на хост не обязательно для панели
|
||||
# # - "9080:9090"
|
||||
# networks:
|
||||
# proxy-net:
|
||||
# ipv4_address: 172.20.0.2 # пример; контроллер слушает на 9090 внутри контейнера
|
||||
#
|
||||
# Контейнер gateway (telemt-api) должен быть в той же сети proxy-net, чтобы:
|
||||
# - резолвилось имя сервиса http://mihomo:9090, или
|
||||
# - использовался IP внутри сети, например http://172.20.0.2:9090
|
||||
#
|
||||
# В environment сервиса gateway (не класть секреты в YAML в git):
|
||||
# MIHOMO_CONTROLLER_URL=http://mihomo:9090
|
||||
# TELEMT_MIHOMO_AUTH=Bearer <тот же секрет, что CLASH_SECRET у Mihomo>
|
||||
#
|
||||
# Вариант A — URL в YAML:
|
||||
# mihomo_base_url: http://mihomo:9090
|
||||
# mihomo_authorization_env: TELEMT_MIHOMO_AUTH
|
||||
#
|
||||
# Вариант B — URL из env (удобно в compose, без правки смонтированного config.yaml):
|
||||
# mihomo_base_url_env: MIHOMO_CONTROLLER_URL
|
||||
# mihomo_authorization_env: TELEMT_MIHOMO_AUTH
|
||||
#
|
||||
# Значение mihomo_authorization_env: полная строка заголовка Authorization (как у authorization_env для Telemt).
|
||||
# Mihomo: тот же compose-сервис (container_name: mihomo, сеть proxy-net, external-controller :9090).
|
||||
# У процесса/контейнера gateway в environment: TELEMT_MIHOMO_AUTH=Bearer ${CLASH_SECRET} (как у mihomo).
|
||||
mihomo_base_url: http://172.20.0.2:9090
|
||||
mihomo_authorization_env: Bearer Ifwrbqifwrbq1995
|
||||
|
||||
# ivx: HTTPS + nginx location /api/ → Telemt; base_url должен заканчиваться на /api/
|
||||
- alias: gt1
|
||||
|
||||
+2
-4
@@ -8,13 +8,11 @@ services:
|
||||
- ./config.compose.yaml:/etc/telemt-gateway/config.yaml:ro
|
||||
environment:
|
||||
CONFIG_PATH: /etc/telemt-gateway/config.yaml
|
||||
# Опционально: Mihomo в той же Docker-сети, что и gateway (см. docs/GATEWAY_RUN.md)
|
||||
# MIHOMO_CONTROLLER_URL: http://mihomo:9090
|
||||
# TELEMT_MIHOMO_AUTH: Bearer ${CLASH_SECRET}
|
||||
# Вместе с Mihomo в config.yaml: TELEMT_MIHOMO_AUTH: Bearer ${CLASH_SECRET}
|
||||
# Доступ к Telemt на хосте Linux (host.docker.internal в config.compose.yaml):
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
# При необходимости подключите к сети с контейнером Mihomo:
|
||||
# С контейнером mihomo в сети proxy-net:
|
||||
# networks:
|
||||
# - proxy-net
|
||||
# networks:
|
||||
|
||||
@@ -86,6 +86,8 @@ servers:
|
||||
- Шлюз проксирует на `{mihomo_base_url}/proxies`, `…/traffic` и т.д. с заголовком `Authorization` из переменной окружения (секрет **не** попадает в фронтенд).
|
||||
- Служебный ответ: `GET /api/{alias}/mihomo/meta` — JSON с полем `controller_base` (без учётных данных) для строки «Подключено к: …» в панели.
|
||||
|
||||
В **config.yaml** задаются только параметры **шлюза** (`mihomo_base_url` / `mihomo_base_url_env`, `mihomo_authorization_env`). Сервис контейнера Mihomo (`build`, `CLASH_SECRET`, сеть `proxy-net` и т.д.) описывается в вашем Docker Compose отдельно; связка URL и переменных для gateway — ниже и в [docker-compose.yml](../docker-compose.yml).
|
||||
|
||||
Поля в конфиге:
|
||||
|
||||
| Поле | Описание |
|
||||
@@ -112,6 +114,8 @@ services:
|
||||
|
||||
За **reverse proxy** (nginx) перед панелью убедитесь, что для WebSocket проксируются заголовки `Upgrade` и `Connection`.
|
||||
|
||||
Если раздел Mihomo отдаёт **400** и в браузере «Ответ не JSON»: проверьте, что `mihomo_authorization_env` — это **имя** env (например `TELEMT_MIHOMO_AUTH`), а полный заголовок `Bearer …` задан в **environment** контейнера gateway (не в YAML). После обновления шлюза прокси Mihomo использует `Rewrite` и сбрасывает `RequestURI` на исходящем запросе — без этого строгий upstream может отвечать 400.
|
||||
|
||||
## Переменные окружения
|
||||
|
||||
| Переменная | Описание |
|
||||
|
||||
+19
-15
@@ -9,6 +9,8 @@ import (
|
||||
)
|
||||
|
||||
// NewMihomoForward proxies /api/{alias}/mihomo/... to Mihomo external-controller (REST + WebSocket).
|
||||
// Используется Rewrite (Go 1.20+): очищается RequestURI и задаётся абсолютный URL — иначе строгий upstream
|
||||
// и WebSocket upgrade могут отвечать 400 (см. аналогично Telemt в forward.go).
|
||||
func NewMihomoForward(
|
||||
target *url.URL,
|
||||
stripPrefix string,
|
||||
@@ -23,27 +25,30 @@ func NewMihomoForward(
|
||||
rt = http.DefaultTransport
|
||||
}
|
||||
rp := &httputil.ReverseProxy{
|
||||
Director: func(req *http.Request) {
|
||||
NormalizeRequestURLPath(req)
|
||||
p := req.URL.Path
|
||||
Rewrite: func(pr *httputil.ProxyRequest) {
|
||||
NormalizeRequestURLPath(pr.In)
|
||||
p := pr.In.URL.Path
|
||||
if !strings.HasPrefix(p, stripPrefix) {
|
||||
return
|
||||
}
|
||||
rest := strings.TrimPrefix(p, stripPrefix)
|
||||
rest = strings.TrimPrefix(rest, "/")
|
||||
q := req.URL.RawQuery
|
||||
rest := strings.TrimPrefix(strings.TrimPrefix(p, stripPrefix), "/")
|
||||
dest := JoinPathPrefix(target, "/", rest)
|
||||
req.URL.Scheme = dest.Scheme
|
||||
req.URL.Host = dest.Host
|
||||
req.URL.Path = dest.Path
|
||||
req.URL.RawQuery = q
|
||||
req.Host = dest.Host
|
||||
req.Header.Del("Authorization")
|
||||
du := *dest
|
||||
du.RawQuery = pr.In.URL.RawQuery
|
||||
out := pr.Out
|
||||
out.URL = &du
|
||||
out.Host = du.Host
|
||||
out.RequestURI = ""
|
||||
out.Proto = "HTTP/1.1"
|
||||
out.ProtoMajor = 1
|
||||
out.ProtoMinor = 1
|
||||
out.Header.Del("Authorization")
|
||||
if auth != "" {
|
||||
req.Header.Set("Authorization", auth)
|
||||
out.Header.Set("Authorization", auth)
|
||||
}
|
||||
},
|
||||
Transport: rt,
|
||||
Transport: rt,
|
||||
FlushInterval: -1,
|
||||
ErrorHandler: func(w http.ResponseWriter, r *http.Request, err error) {
|
||||
errHandler(w, r, err)
|
||||
},
|
||||
@@ -70,4 +75,3 @@ func MihomoJSONError(w http.ResponseWriter, code, msg string) {
|
||||
"error": map[string]string{"code": code, "message": msg},
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -28,9 +28,20 @@ export function mihomoWsUrl(alias: string, path: string): string {
|
||||
return `${wsBase}/api/${encodeURIComponent(alias)}/mihomo/${p}`;
|
||||
}
|
||||
|
||||
async function parseMihomoBody(res: Response): Promise<unknown> {
|
||||
const text = await res.text();
|
||||
if (!text) return null;
|
||||
try {
|
||||
return JSON.parse(text);
|
||||
} catch {
|
||||
const snip = text.length > 200 ? `${text.slice(0, 200)}…` : text;
|
||||
throw new ApiError(`Ответ не JSON (HTTP ${res.status}): ${snip}`, res.status, text);
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchMihomoMeta(alias: string): Promise<MihomoMetaResponse> {
|
||||
const res = await fetch(mihomoUrl(alias, 'meta'));
|
||||
const body = (await parseJson(res)) as Record<string, unknown> | null;
|
||||
const body = (await parseMihomoBody(res)) as Record<string, unknown> | null;
|
||||
if (res.status === 404) {
|
||||
throw new ApiError('Mihomo не настроен для этой ноды', 404, body);
|
||||
}
|
||||
@@ -45,7 +56,7 @@ export async function fetchMihomoMeta(alias: string): Promise<MihomoMetaResponse
|
||||
|
||||
export async function fetchMihomoJson<T>(alias: string, path: string): Promise<T> {
|
||||
const res = await fetch(mihomoUrl(alias, path));
|
||||
const body = await parseJson(res);
|
||||
const body = await parseMihomoBody(res);
|
||||
if (res.status === 404) {
|
||||
throw new ApiError('Mihomo не настроен для этой ноды', 404, body);
|
||||
}
|
||||
@@ -62,11 +73,11 @@ export async function mihomoPut(alias: string, path: string, jsonBody: unknown):
|
||||
body: JSON.stringify(jsonBody)
|
||||
});
|
||||
if (res.status === 404) {
|
||||
const body = await parseJson(res);
|
||||
const body = await parseMihomoBody(res);
|
||||
throw new ApiError('Mihomo не настроен для этой ноды', 404, body);
|
||||
}
|
||||
if (!res.ok) {
|
||||
const body = await parseJson(res);
|
||||
const body = await parseMihomoBody(res);
|
||||
throw new ApiError(`Mihomo PUT HTTP ${res.status}`, res.status, body);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user