3X-UI:强大的Xray-core网页管理面板

1,692 阅读3分钟

3X-UI:强大的Xray-core网页管理面板

项目描述

3X-UI是一个基于网页的高级开源控制面板,专为管理Xray-core服务器而设计。作为原始X-UI项目的增强版本,它提供了用户友好的界面,用于配置和监控各种VPN和代理协议,包括VMess、VLESS、Trojan、Shadowsocks等。

重要提示:本项目仅用于个人使用和通信,请勿将其用于非法目的,请勿在生产环境中使用。

功能特性

  • 多协议支持:全面支持VMess、VLESS、Trojan、Shadowsocks等多种代理协议
  • 网页管理界面:直观的Web-based控制面板,无需命令行操作
  • 流量监控:实时监控用户流量使用情况,支持流量限制和到期时间设置
  • 客户端管理:细粒度的客户端管理,支持多用户配置
  • 安全特性:集成Fail2Ban支持,防止暴力破解攻击
  • 订阅服务:自动生成订阅链接,支持多种客户端订阅
  • 多语言支持:支持中文、英文、波斯语、阿拉伯语等多种语言界面
  • 自动化安装:提供一键安装脚本,简化部署过程

安装指南

系统要求

  • Linux操作系统(Ubuntu、Debian、CentOS等)
  • GLIBC 2.32或更高版本
  • root权限

一键安装

bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)

手动安装

  1. 下载对应架构的Xray-core二进制文件
  2. 配置数据库和运行环境
  3. 启动Web服务

依赖项

  • Xray-core v25.6.8或更高版本
  • SQLite数据库
  • 必要的系统工具(wget、curl、tar等)

使用说明

基本使用

  1. 访问面板:安装完成后,通过浏览器访问服务器IP和端口(默认端口:2053)
  2. 登录系统:使用默认用户名和密码(admin/admin)登录
  3. 配置入站协议:在"Inbounds"页面添加和配置代理协议
  4. 管理客户端:为每个入站协议添加和管理用户客户端
  5. 监控流量:在仪表板查看实时流量和使用情况

示例配置

创建VMess入站示例:

{
  "protocol": "vmess",
  "port": 443,
  "settings": {
    "clients": [
      {
        "id": "自动生成的UUID",
        "email": "user@example.com",
        "enable": true
      }
    ]
  },
  "streamSettings": {
    "network": "ws",
    "security": "tls"
  }
}

API使用

3X-UI提供RESTful API接口,支持程序化管理:

# 获取所有入站配置
curl -X POST http://localhost:2053/panel/api/inbounds/list \
  -H "Authorization: Bearer <token>"

核心代码

主程序入口

package main

import (
	"x-ui/config"
	"x-ui/database"
	"x-ui/logger"
	"x-ui/web"
	"x-ui/web/global"
)

func runWebServer() {
	// 初始化日志系统
	logger.InitLogger(logging.INFO)
	
	// 初始化数据库
	err := database.InitDB(config.GetDBPath())
	if err != nil {
		log.Fatalf("Error initializing database: %v", err)
	}
	
	// 启动Web服务器
	server := web.NewServer()
	global.SetWebServer(server)
	err = server.Start()
	if err != nil {
		log.Fatalf("Error starting web server: %v", err)
	}
}

数据库模型

package database

import (
	"gorm.io/gorm"
	"x-ui/database/model"
)

// 初始化数据表结构
func initModels() error {
	models := []any{
		&model.User{},           // 用户表
		&model.Inbound{},        // 入站配置表
		&model.Setting{},        // 系统设置表
		&model.InboundClientIps{}, // 客户端IP记录表
	}
	
	for _, model := range models {
		if err := db.AutoMigrate(model); err != nil {
			return err
		}
	}
	return nil
}

// 初始化默认用户
func initUser() error {
	user := &model.User{
		Username: "admin",
		Password: "加密后的密码",
	}
	return db.Create(user).Error
}

Xray配置生成

package xray

// 生成Xray配置文件
func GenerateConfig(inbounds []*model.Inbound) (string, error) {
	config := map[string]interface{}{
		"log": map[string]interface{}{
			"loglevel": "warning",
		},
		"inbounds":  generateInboundsConfig(inbounds),
		"outbounds": generateOutboundsConfig(),
		"routing":   generateRoutingConfig(),
	}
	
	configJson, err := json.MarshalIndent(config, "", "  ")
	if err != nil {
		return "", err
	}
	
	return string(configJson), nil
}

// 生成入站配置
func generateInboundsConfig(inbounds []*model.Inbound) []interface{} {
	var configInbounds []interface{}
	
	for _, inbound := range inbounds {
		if !inbound.Enable {
			continue
		}
		
		inboundConfig := map[string]interface{}{
			"port":     inbound.Port,
			"protocol": inbound.Protocol,
			"settings": inbound.Settings,
			"sniffing": map[string]interface{}{
				"enabled":      true,
				"destOverride": []string{"http", "tls"},
			},
		}
		
		configInbounds = append(configInbounds, inboundConfig)
	}
	
	return configInbounds
}

订阅服务

package sub

// 处理订阅请求
func (s *SubService) GetSubs(subId string, host string) ([]string, string, error) {
	inbounds, err := s.getInboundsBySubId(subId)
	if err != nil {
		return nil, "", err
	}

	var result []string
	for _, inbound := range inbounds {
		clients, err := s.inboundService.GetClients(inbound)
		if err != nil {
			continue
		}
		
		for _, client := range clients {
			if client.Enable && client.SubID == subId {
				link := s.getLink(inbound, client.Email)
				result = append(result, link)
			}
		}
	}
	
	// 返回Base64编码的订阅内容
	if s.subEncrypt {
		return []string{base64.StdEncoding.EncodeToString([]byte(strings.Join(result, "\n")))}, header, nil
	}
	
	return result, header, nil
}

流量统计

package job

// 流量统计任务
func (j *XrayTrafficJob) Run() {
	if !j.xrayService.IsXrayRunning() {
		return
	}
	
	// 获取流量数据
	traffics, clientTraffics, err := j.xrayService.GetXrayTraffic()
	if err != nil {
		return
	}
	
	// 更新数据库中的流量统计
	err, needRestart0 := j.inboundService.AddTraffic(traffics, clientTraffics)
	if err != nil {
		logger.Warning("add inbound traffic failed:", err)
	}
	
	// 如果需要重启服务
	if needRestart0 {
		j.xrayService.SetToNeedRestart()
	}
}