Конфигурации нод
Концепция
Section titled “Концепция”Конфигурация — это переиспользуемый шаблон Xray inbound. Создаёшь его один раз в админке, потом привязываешь к любым нодам. При привязке агент применяет inbound к Xray на этой ноде.
server_configs (шаблоны) node_configs (привязки)┌─────────────────────┐ ┌──────────────────────────────┐│ VLESS TCP Reality │────┐ │ node: NL-1, port: 443 ││ VLESS XHTTP TLS │ ├───▶│ node: DE-1, port: 443 ││ Trojan WS TLS │ │ │ node: US-1, port: 8443 │└─────────────────────┘ └───▶│ node: JP-1, port: 443 │ └──────────────────────────────┘Поддерживаемые комбинации
Section titled “Поддерживаемые комбинации”| Протокол | Транспорт | Безопасность | Кейс |
|---|---|---|---|
| VLESS | TCP | Reality | Цензурозащищённый, без CDN |
| VLESS | TCP | XTLS | Максимальная скорость |
| VLESS | XHTTP | TLS | CDN (Cloudflare), обход DPI |
| VLESS | XHTTP | Reality | Новый транспорт + Reality |
| VLESS | WS | TLS | Классика с CDN |
| VLESS | gRPC | TLS | CDN, мобильные сети |
| Trojan | WS | TLS | Альтернатива VLESS |
| Trojan | gRPC | TLS | CDN-compatible |
| VMess | WS | TLS | Обратная совместимость |
| Shadowsocks | TCP | — | Простой, быстрый |
server_configs — шаблоны конфигураций
Section titled “server_configs — шаблоны конфигураций”id uuid PRIMARY KEYname varchar -- "VLESS TCP Reality (Fast)"description textprotocol enum(vless, vmess, trojan, shadowsocks)transport enum(tcp, ws, grpc, xhttp, quic)security enum(none, tls, reality)
-- Настройки транспорта (зависят от поля transport)transport_settings jsonb-- ws: { "path": "/ws", "host": "domain.com" }-- grpc: { "serviceName": "grpc" }-- xhttp: { "path": "/xhttp", "mode": "stream-one" }
-- Настройки безопасности (зависят от поля security)security_settings jsonb-- tls: { "serverName": "domain.com" }-- reality: { "dest": "www.google.com:443", "serverNames": [...],-- "privateKey": "...", "publicKey": "...",-- "shortIds": [...], "fingerprint": "chrome" }
-- VLESS-специфичные настройкиflow varchar null -- "xtls-rprx-vision" для Reality/XTLS, иначе null
sniffing bool DEFAULT trueis_active bool DEFAULT truecreated_at timestamptzupdated_at timestamptznode_server_configs — привязки конфига к ноде
Section titled “node_server_configs — привязки конфига к ноде”id uuid PRIMARY KEYnode_id uuid REFERENCES nodes(id)config_id uuid REFERENCES server_configs(id)
port int -- порт на конкретной ноде (может отличаться)tag varchar -- xray inbound tag: "vless-reality-nl1" (auto или custom)
-- TLS-сертификаты (если security = tls)-- Хранятся здесь, т.к. у каждой ноды свой домен и свой сертификатtls_cert text nulltls_key text null
status enum(pending, applied, error) DEFAULT 'pending'error_msg text nullapplied_at timestamptz nullcreated_at timestamptz
UNIQUE (node_id, config_id)UNIQUE (node_id, tag)UNIQUE (node_id, port)Как конфиг превращается в Xray inbound
Section titled “Как конфиг превращается в Xray inbound”Панель собирает JSON для Xray из полей server_config + node_server_config:
func BuildInbound(cfg *ServerConfig, binding *NodeServerConfig) (*XrayInbound, error) { inbound := &XrayInbound{ Tag: binding.Tag, Port: binding.Port, Protocol: string(cfg.Protocol), Sniffing: XraySniffing{ Enabled: cfg.Sniffing, DestOverride: []string{"http", "tls", "quic"}, }, Settings: buildProtocolSettings(cfg), StreamSettings: buildStreamSettings(cfg, binding), } return inbound, nil}
func buildStreamSettings(cfg *ServerConfig, binding *NodeServerConfig) XrayStreamSettings { s := XrayStreamSettings{ Network: string(cfg.Transport), Security: string(cfg.Security), }
switch cfg.Transport { case TransportWS: s.WSSettings = &XrayWSSettings{ Path: cfg.TransportSettings["path"].(string), } case TransportXHTTP: s.XHTTPSettings = &XrayXHTTPSettings{ Path: cfg.TransportSettings["path"].(string), Mode: cfg.TransportSettings["mode"].(string), } case TransportGRPC: s.GRPCSettings = &XrayGRPCSettings{ ServiceName: cfg.TransportSettings["serviceName"].(string), } }
switch cfg.Security { case SecurityTLS: s.TLSSettings = &XrayTLSSettings{ ServerName: cfg.SecuritySettings["serverName"].(string), Certificates: []XrayCert{{ Certificate: binding.TLSCert, Key: binding.TLSKey, }}, } case SecurityReality: s.RealitySettings = &XrayRealitySettings{ Dest: cfg.SecuritySettings["dest"].(string), ServerNames: cfg.SecuritySettings["serverNames"].([]string), PrivateKey: cfg.SecuritySettings["privateKey"].(string), ShortIds: cfg.SecuritySettings["shortIds"].([]string), Fingerprint: cfg.SecuritySettings["fingerprint"].(string), } }
return s}Флоу в админке
Section titled “Флоу в админке”1. Создание конфига (конструктор)
Section titled “1. Создание конфига (конструктор)”Шаг 1: Название "VLESS TCP Reality — Premium"
Шаг 2: Протокол ○ VLESS ○ Trojan ○ VMess ○ Shadowsocks
Шаг 3: Транспорт ○ TCP ○ WebSocket ○ gRPC ○ XHTTP
Шаг 4: Безопасность ○ TLS ● Reality ○ None (недоступные комбинации задизейблены)
Шаг 5: Настройки (зависят от выбора) Reality: Destination: [ www.google.com:443 ] Server names: [ www.google.com ] Private key: [ генерируется ] [↻ regenerate] Public key: [ генерируется ] [copy] Short IDs: [ генерируется ] [+ добавить] Fingerprint: [ chrome ▾ ] Flow: [ xtls-rprx-vision ▾ ]2. Привязка конфига к ноде
Section titled “2. Привязка конфига к ноде”На странице ноды или конфига:
Нода: NL-1 (Netherlands)
Привязанные конфиги:┌──────────────────────────┬──────┬────────────┬─────────┐│ Конфиг │ Порт │ Тег │ Статус │├──────────────────────────┼──────┼────────────┼─────────┤│ VLESS TCP Reality │ 443 │ vless-real │ ✓ applied││ VLESS XHTTP TLS │ 8443 │ vless-xhttp│ ✓ applied│└──────────────────────────┴──────┴────────────┴─────────┘
[+ Привязать конфиг] Конфиг: [ VLESS TCP Reality ▾ ] Порт: [ 443 ] Тег: [ vless-reality-nl1 ] (auto) TLS сертификат: (если нужен) [ Загрузить cert ] [ Загрузить key ]3. Применение
Section titled “3. Применение”При нажатии “Привязать”:
- Создаётся запись в
node_server_configsсо статусомpending - Воркер enqueue задачу
apply_config apply_config: собирает Xray JSON → gRPCAddInboundк агенту- Статус обновляется в
appliedилиerror
Subscription link
Section titled “Subscription link”При генерации ссылки для пользователя панель итерирует по всем node_server_configs с status = 'applied' для нод, доступных по плану, и генерирует connection string для каждого:
func BuildSubscriptionConfig(userID string, nodes []NodeWithConfigs) []string { var links []string
for _, node := range nodes { for _, binding := range node.AppliedConfigs { link := buildLink(userID, node, binding) // vless://UUID@node.host:443?type=tcp&security=reality&...#NL-1 Reality links = append(links, link) } }
return links}Пользователь получает все доступные серверы одним импортом.
# КонфигиGET /api/v1/admin/server-configsPOST /api/v1/admin/server-configsGET /api/v1/admin/server-configs/:idPATCH /api/v1/admin/server-configs/:idDELETE /api/v1/admin/server-configs/:id
# ПривязкиGET /api/v1/admin/nodes/:id/configsPOST /api/v1/admin/nodes/:id/configs # привязать конфиг к нодеDELETE /api/v1/admin/nodes/:id/configs/:bindingId # отвязатьPOST /api/v1/admin/nodes/:id/configs/:bindingId/apply # переприменить