Merge branch 'main' into 3x-ui

This commit is contained in:
心隨緣動
2025-08-22 01:44:00 +08:00
committed by GitHub
61 changed files with 4568 additions and 1385 deletions
+2 -2
View File
@@ -731,8 +731,8 @@ class RealityStreamSettings extends XrayCommonClass {
constructor(
show = false,
xver = 0,
dest = 'google.com:443',
serverNames = 'google.com,www.google.com',
dest = 'tesla.com:443',
serverNames = 'tesla.com,www.tesla.com',
privateKey = '',
minClientVer = '',
maxClientVer = '',
+2 -2
View File
@@ -22,7 +22,7 @@ class AllSetting {
this.tgBotBackup = false;
this.tgBotLoginNotify = true;
this.tgCpu = 80;
this.tgLang = "en-US";
this.tgLang = "zh-CN";
this.twoFactorEnable = false;
this.twoFactorToken = "";
this.xrayTemplateConfig = "";
@@ -58,4 +58,4 @@ class AllSetting {
equals(other) {
return ObjectUtil.equals(this, other);
}
}
}
+4 -4
View File
@@ -817,11 +817,11 @@ class LanguageManager {
if (LanguageManager.isSupportLanguage(lang)) {
CookieManager.setCookie("lang", lang, 150);
} else {
CookieManager.setCookie("lang", "en-US", 150);
CookieManager.setCookie("lang", "zh-CN", 150);
window.location.reload();
}
} else {
CookieManager.setCookie("lang", "en-US", 150);
CookieManager.setCookie("lang", "zh-CN", 150);
window.location.reload();
}
}
@@ -831,7 +831,7 @@ class LanguageManager {
static setLanguage(language) {
if (!LanguageManager.isSupportLanguage(language)) {
language = "en-US";
language = "zh-CN";
}
CookieManager.setCookie("lang", language, 150);
@@ -884,4 +884,4 @@ class FileManager {
link.remove();
}
}
}
+5
View File
@@ -26,6 +26,7 @@ func (a *XUIController) initRouter(g *gin.RouterGroup) {
g.GET("/inbounds", a.inbounds)
g.GET("/settings", a.settings)
g.GET("/xray", a.xraySettings)
g.GET("/navigation", a.navigation)
a.inboundController = NewInboundController(g)
a.settingController = NewSettingController(g)
@@ -47,3 +48,7 @@ func (a *XUIController) settings(c *gin.Context) {
func (a *XUIController) xraySettings(c *gin.Context) {
html(c, "xray.html", "pages.xray.title", nil)
}
func (a *XUIController) navigation(c *gin.Context) {
html(c, "navigation.html", "pages.navigation.title", nil)
}
+6 -1
View File
@@ -64,6 +64,11 @@
icon: 'tool',
title: '{{ i18n "menu.xray"}}'
},
{
key: '{{ .base_path }}panel/navigation',
icon: 'link',
title: '{{ i18n "menu.navigation"}}'
},
{
key: '{{ .base_path }}logout/',
icon: 'logout',
@@ -100,4 +105,4 @@
template: `{{template "component/sidebar/content"}}`,
});
</script>
{{end}}
{{end}}
+3 -3
View File
@@ -48,7 +48,7 @@
<a-textarea v-model="inbound.stream.reality.privateKey"></a-textarea>
</a-form-item>
<a-form-item label=" ">
<a-button type="primary" icon="import" @click="getNewX25519Cert">Get New Cert</a-button>
<a-button type="primary" icon="import" @click="getNewX25519Cert">Get New Cert(随机获取新证书)</a-button>
</a-form-item>
<a-form-item label="mldsa65 Seed">
<a-textarea v-model="inbound.stream.reality.mldsa65Seed"></a-textarea>
@@ -57,7 +57,7 @@
<a-textarea v-model="inbound.stream.reality.settings.mldsa65Verify"></a-textarea>
</a-form-item>
<a-form-item label=" ">
<a-button type="primary" icon="import" @click="getNewmldsa65">Get New Seed</a-button>
<a-button type="primary" icon="import" @click="getNewmldsa65">Get New Seed(获取Mldsa65数值)</a-button>
</a-form-item>
</template>
{{end}}
{{end}}
+9 -7
View File
@@ -219,20 +219,20 @@
</a-card>
</a-col>
<a-col :sm="24" :lg="12">
<a-card title='3X-UI' hoverable>
<a rel="noopener" href="https://github.com/MHSanaei/3x-ui/releases" target="_blank">
<a-card title='3X-UI〕中文优化版' hoverable>
<a rel="noopener" href="https://github.com/xeefei/3x-ui/releases" target="_blank">
<a-tag color="green">
<span>v{{ .cur_ver }}</span>
</a-tag>
</a>
<a rel="noopener" href="https://t.me/XrayUI" target="_blank">
<a rel="noopener" href="https://t.me/is_Chat_Bot" target="_blank">
<a-tag color="green">
<span>@XrayUI</span>
<span>TG私聊交流</span>
</a-tag>
</a>
<a rel="noopener" href="https://github.com/MHSanaei/3x-ui/wiki" target="_blank">
<a rel="noopener" href="https://t.me/XUI_CN" target="_blank">
<a-tag color="purple">
<span>{{ i18n "pages.index.documentation" }}</span>
<span>3X-UI〕中文交流群</span>
</a-tag>
</a>
</a-card>
@@ -253,6 +253,8 @@
</template>
</a-tooltip>
</a-tag>
<a rel="noopener" href="https://ping.pe" target="_blank"><a-tag color="green">端口检测</a-tag></a>
<a rel="noopener" href="https://www.speedtest.net" target="_blank"><a-tag color="green">网络测速</a-tag></a>
</a-card>
</a-col>
<a-col :sm="24" :lg="12">
@@ -911,4 +913,4 @@ ${dateTime}
},
});
</script>
{{ template "page/body_end" .}}
{{ template "page/body_end" .}}
+12 -12
View File
@@ -1,7 +1,7 @@
{{define "modals/ruleModal"}}
<a-modal id="rule-modal" v-model="ruleModal.visible" :title="ruleModal.title" @ok="ruleModal.ok" :confirm-loading="ruleModal.confirmLoading" :closable="true" :mask-closable="false" :ok-text="ruleModal.okText" cancel-text='{{ i18n "close" }}' :class="themeSwitcher.currentTheme">
<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
<a-form-item label='Domain Matcher'>
<a-form-item label='{{ i18n "pages.xray.rules.DomainMatcher" }}'>
<a-select v-model="ruleModal.rule.domainMatcher" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option v-for="dm in ['','hybrid','linear']" :value="dm">[[ dm ]]</a-select-option>
</a-select>
@@ -11,7 +11,7 @@
<a-tooltip>
<template slot="title">
<span>{{ i18n "pages.xray.rules.useComma" }}</span>
</template> Source IPs <a-icon type="question-circle"></a-icon>
</template> {{ i18n "pages.xray.rules.SourceIPs" }} <a-icon type="question-circle"></a-icon>
</a-tooltip>
</template>
<a-input v-model.trim="ruleModal.rule.source"></a-input>
@@ -21,22 +21,22 @@
<a-tooltip>
<template slot="title">
<span>{{ i18n "pages.xray.rules.useComma" }}</span>
</template> Source Port <a-icon type="question-circle"></a-icon>
</template> {{ i18n "pages.xray.rules.SourcePort" }} <a-icon type="question-circle"></a-icon>
</a-tooltip>
</template>
<a-input v-model.trim="ruleModal.rule.sourcePort"></a-input>
</a-form-item>
<a-form-item label='Network'>
<a-form-item label='{{ i18n "pages.xray.rules.Network" }}'>
<a-select v-model="ruleModal.rule.network" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option v-for="x in ['','TCP','UDP','TCP,UDP']" :value="x">[[ x ]]</a-select-option>
</a-select>
</a-form-item>
<a-form-item label='Protocol'>
<a-form-item label='{{ i18n "pages.xray.rules.Protocol" }}'>
<a-select v-model="ruleModal.rule.protocol" mode="multiple" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option v-for="x in ['http','tls','bittorrent','quic']" :value="x">[[ x ]]</a-select-option>
</a-select>
</a-form-item>
<a-form-item label='Attributes'>
<a-form-item label='{{ i18n "pages.xray.rules.Attributes" }}'>
<a-button icon="plus" size="small" :style="{ marginLeft: '10px' }" @click="ruleModal.rule.attrs.push(['', ''])"></a-button>
</a-form-item>
<a-form-item :wrapper-col="{span: 24}">
@@ -64,7 +64,7 @@
<a-tooltip>
<template slot="title">
<span>{{ i18n "pages.xray.rules.useComma" }}</span>
</template> Domain <a-icon type="question-circle"></a-icon>
</template> {{ i18n "pages.xray.rules.Domain" }} <a-icon type="question-circle"></a-icon>
</a-tooltip>
</template>
<a-input v-model.trim="ruleModal.rule.domain"></a-input>
@@ -74,7 +74,7 @@
<a-tooltip>
<template slot="title">
<span>{{ i18n "pages.xray.rules.useComma" }}</span>
</template> User <a-icon type="question-circle"></a-icon>
</template> {{ i18n "pages.xray.rules.User" }} <a-icon type="question-circle"></a-icon>
</a-tooltip>
</template>
<a-input v-model.trim="ruleModal.rule.user"></a-input>
@@ -84,17 +84,17 @@
<a-tooltip>
<template slot="title">
<span>{{ i18n "pages.xray.rules.useComma" }}</span>
</template> Port <a-icon type="question-circle"></a-icon>
</template> {{ i18n "pages.xray.rules.Port" }} <a-icon type="question-circle"></a-icon>
</a-tooltip>
</template>
<a-input v-model.trim="ruleModal.rule.port"></a-input>
</a-form-item>
<a-form-item label='Inbound Tags'>
<a-form-item label='{{ i18n "pages.xray.rules.InboundTag" }}'>
<a-select v-model="ruleModal.rule.inboundTag" mode="multiple" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option v-for="tag in ruleModal.inboundTags" :value="tag">[[ tag ]]</a-select-option>
</a-select>
</a-form-item>
<a-form-item label='Outbound Tag'>
<a-form-item label='{{ i18n "pages.xray.rules.OutboundTag" }}'>
<a-select v-model="ruleModal.rule.outboundTag" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option v-for="tag in ruleModal.outboundTags" :value="tag">[[ tag ]]</a-select-option>
</a-select>
@@ -104,7 +104,7 @@
<a-tooltip>
<template slot="title">
<span>{{ i18n "pages.xray.balancer.balancerDesc" }}</span>
</template> Balancer Tag <a-icon type="question-circle"></a-icon>
</template> {{ i18n "pages.xray.rules.BalancerTag" }} <a-icon type="question-circle"></a-icon>
</a-tooltip>
</template>
<a-select v-model="ruleModal.rule.balancerTag" :dropdown-class-name="themeSwitcher.currentTheme">
+165
View File
@@ -0,0 +1,165 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>实用导航&技巧</title>
<style>
body {
background-color: #151F31;
color: white;
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
display: flex;
}
.sidebar {
width: 150px;
background-color: #151F31;
padding: 20px;
}
.sidebar h2 {
color: #fff;
margin-top: 0;
}
.sidebar button {
background-color: #2C3E56;
color: #008000; /* 绿色字体 */
border: none;
padding: 10px 20px;
margin-bottom: 10px;
cursor: pointer;
display: block;
width: 100%;
border-radius: 15px; /* 增加圆角幅度 */
font-weight: bold; /* 加粗字体 */
}
.sidebar button:hover {
background-color: #4A90E2;
}
.sidebar .friend-links {
margin-top: auto;
text-align: center;
margin-bottom: 12px; /* 调整友情链接下边距 */
}
.sidebar .friend-links a {
color: #0080FF; /* 蓝色字体 */
text-decoration: none;
display: block;
margin-bottom: 10px;
}
.separator {
width: 15px;
background-color: #34495e;
}
.content {
flex: 1;
padding: 20px;
padding-top: 0; /* 移除顶部空白 */
}
</style>
</head>
<body>
<div class="sidebar">
<button onclick="history.back()">返回上一步</button>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<div class="friend-links">
<a href="https://chat.openai.com/">ChatGPT</a>
<a href="https://github.com/xeefei/3x-ui">项目地址</a>
<a href="https://t.me/XUI_CN">3X-UI交流群</a>
<a href="https://www.youtube.com/results?search_query=4k%E6%B5%8B%E9%80%9F">油管4K测速</a>
<a href="https://whatismyipaddress.com/">我的IP查询</a>
<a href="https://translate.google.com/?hl=zh-CN">Google翻译</a>
<a href="https://xtls.github.io/">Project X</a>
<a href="https://t.me/is_Haotian_Bot">预留&占位</a>
<a href="https://t.me/is_Chat_Bot">联系作者</a>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<button onclick="window.scrollTo(0, 0)">回滚至顶部</button>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<button onclick="history.back()">返回到面板</button>
</div>
</div>
<div class="separator"></div>
<div class="content">
<h3>一、【3x-ui】中文交流群:<a href="https://t.me/XUI_CN">https://t.me/XUI_CN</a></h3>
<h3> 【3x-ui】详细安装流程步骤:<a href="https://xeefei.blogspot.com/2025/07/3x-ui.html">https://xeefei.blogspot.com/2025/07/3x-ui.html</a></h3>
<h3>二、判断VPS服务器的IP是否【送中】?</h3>
<p>***点击打开:<a href="https://music.youtube.com/">https://music.youtube.com/</a>,能正常打开访问,就代表【没送中】,反之就是送中了。</p>
<p>***如果送中了如何解决去【拉回来】?</p>
<p>1:关闭/取消登录了谷歌账户的APP定位权限/授权;2:将常用的一个谷歌账号的位置记录功能打开;3:在电脑上打开Chrome/谷歌浏览器,登录开了位置记录功能的谷歌账号,安装Location Guard拓展插件<a href="https://chrome.google.com/webstore/detail/location-guard/cfohepagpmnodfdmjliccbbigdkfcgia">https://chrome.google.com/webstore/detail/location-guard/cfohepagpmnodfdmjliccbbigdkfcgia</a>(也可在其他支持此插件的浏览器使用);4:打开Location Guard插件,选择Fixed Location,并在给出的地图上单击,即可标记上你想要IP所处的国家/地区
Google IP定位错误,使用Location Guard修改;5:转换到Options选项,Default level默认设置为Use fixed location6:打开谷歌地图google.com/maps,点击右下角定位授权图标,使google maps获取当前“我的GPS位置”
Google IP定位错误,使用Location Guard修改GPS位置地址;7:谷歌搜索my ip,即可看到谷歌IP定位到了刚才地图上标记的位置;8:在此网页向谷歌报告IP问题:<a href="https://support.google.com/websearch/workflow/9308722">https://support.google.com/websearch/workflow/9308722</a></p>
<h3>三、在自己的VPS服务器部署【订阅转换】功能</h3>
<p>如何把vless/vmess等协议转换成Clash/Surge等软件支持的格式?
1、进入脚本输入x-ui命令调取面板,选择第【24】选项安装订阅转换模块,
2、等待安装【订阅转换】成功之后,访问地址:你的IP:18080(端口号)进行转换,
3、因为在转换过程中需要调取后端API,所以请确保端口25500是打开放行的,
4、在得到【转换链接】之后,只要你的VPS服务器25500端口是能ping通的,就能导入Clash/Surge等软件成功下载配置,
5、此功能集成到3x-ui面板中,是为了保证安全,通过调取24选项把【订阅转换】功能部署在自己的VPS中,不会造成链接泄露。</p>
<h3>四、如何保护自己的IP不被墙被封?</h3>
<p>1、使用的代理协议要安全,加密是必备,推荐使用vless+reality+vision协议组合,
2、因为有时节点会共享,在不同的地区,多个省份之间不要共同连接同一个IP,
3、连接同一个IP就算了,不要同一个端口,不要同IP+同端口到处漫游,要分开,
4、同一台VPS,不要在一天内一直大流量去下载东西使用,不要流量过高要切换,
5、创建【入站协议】的时候,尽量用【高位端口】,比如40000--65000之间的端口号。
提醒:为什么在特殊时期,比如:两会,春节等被封得最严重最惨?
尼玛同一个IP+同一个端口号,多个省份去漫游,跟开飞机场一样!不封你,封谁的IP和端口?
总结:不要多终端/多省份/多个朋友/共同使用同一个IP和端口号!使用3x-ui多创建几个【入站】,
多做几条备用,各用各的!各行其道才比较安全!GFW的思维模式是干掉机场,机场的特征个人用户不要去沾染,自然IP就保护好了。</p>
<h3>五、检测IP纯净度的方法:</h3>
<p>网址:<a href="https://scamalytics.com/">https://scamalytics.com/</a>,输入IP进行检测,看【欺诈分数】,分数越高IP越脏。</p>
<h3>六、常见的翻墙软件/工具:</h3>
<ol>
<p>1、Windows系统v2rayN<a href="https://github.com/2dust/v2rayN">https://github.com/2dust/v2rayN</a></p>
<p>2、安卓手机版【v2rayNG】:<a href="https://github.com/2dust/v2rayNG">https://github.com/2dust/v2rayNG</a></p>
<p>3、苹果手机IOS【小火箭】:<a href="https://apple02.com/">https://apple02.com/</a></p>
<p>4、苹果MacOS电脑【Clash Verge】:<a href="https://github.com/clash-verge-rev/clash-verge-rev/releases">https://github.com/clash-verge-rev/clash-verge-rev/releases</a>或v2rayN<a href="https://github.com/2dust/v2rayN">https://github.com/2dust/v2rayN</a></p>
</ol>
<h3>七、查看节点【指定端口】的网络连接数/命令:</h3>
<p>netstat -ntu | grep :节点端口 | grep ESTABLISHED | awk '{print $5}'</p>
<h3>八、用3x-ui如何实现【自己偷自己】?</h3>
<p>其实很简单,只要你为面板设置了证书,
开启了HTTPS登录,就可以将3x-ui自身作为web server
无需Nginx等,这里给一个示例:
其中目标网站(Dest)请填写面板监听端口,
可选域名(SNI)填写面板登录域名,
如果您使用其他web server(如nginx)等,
将目标网站改为对应监听端口也可。
需要说明的是,如果您处于白名单地区,自己“偷”自己并不适合你;其次,可选域名一项实际上可以填写任意SNI,只要客户端保持一致即可,不过并不推荐这样做。</p>
<h3>九、【接码】网站:</h3>
<p>网址:<a href="https://sms-activate.org/cn">https://sms-activate.org/cn</a>,直接注册账号购买。</p>
<h3>十、一些MJJ经常逛的网站和群组:</h3>
<ol>
<p>1、NodeSeek论坛:<a href="https://www.nodeseek.com/">https://www.nodeseek.com/</a></p>
<p>2、V2EX论坛:<a href="https://www.v2ex.com/">https://www.v2ex.com/</a></p>
<p>3、搬瓦工TG群:<a href="https://t.me/BWHOfficial">https://t.me/BWHOfficial</a></p>
<p>4、Xray的官方群:<a href="https://t.me/projectXray">https://t.me/projectXray</a></p>
<p>5、Dmit交流群:<a href="https://t.me/DmitChat">https://t.me/DmitChat</a></p>
<p>6、白丝云用户群:<a href="https://t.me/+VHZLKELTQyzPNgOV">https://t.me/+VHZLKELTQyzPNgOV</a></p>
<p>7、NameSilo域名注册:<a href="https://www.namesilo.com/">https://www.namesilo.com/</a></p>
</ol>
<h3>十一、若此项目对你有帮助,你正想购买VPS的话,可以走一下我的AFF:</h3>
<ol>
<p>1、搬瓦工GIA线路:<a href="https://bandwagonhost.com/aff.php?aff=75015">https://bandwagonhost.com/aff.php?aff=75015</a></p>
<p>2、Dmit高端GIA<a href="https://www.dmit.io/aff.php?aff=9326">https://www.dmit.io/aff.php?aff=9326</a></p>
<p>3、白丝云【4837】:<a href="https://cloudsilk.io/aff.php?aff=706">https://cloudsilk.io/aff.php?aff=706</a></p>
</ol>
<h3>十二、项目〔声明和注意〕</h3>
<ol>
<p>1、声明: 此项目仅供个人学习、交流使用,请遵守当地法律法规,勿用于非法用途;请勿用于生产环境;</a></p>
<p>2、注意: 在使用此项目和〔教程〕过程中,若因违反以上声明使用规则而产生的一切后果由使用者自负。</a></p>
</ol>
</div>
</body>
</html>
+9 -3
View File
@@ -1,4 +1,10 @@
{{define "settings/panel/general"}}
<style>
.red-placeholder input::-webkit-input-placeholder { color: red !important; }
.red-placeholder input::-moz-placeholder { color: red !important; }
.red-placeholder input:-ms-input-placeholder { color: red !important; }
.red-placeholder input::placeholder { color: red !important; }
</style>
<a-collapse default-active-key="1">
<a-collapse-panel key="1" header='{{ i18n "pages.xray.generalConfigs"}}'>
<a-setting-list-item paddings="small">
@@ -97,14 +103,14 @@
<template #title>{{ i18n "pages.settings.publicKeyPath"}}</template>
<template #description>{{ i18n "pages.settings.publicKeyPathDesc"}}</template>
<template #control>
<a-input type="text" v-model="allSetting.webCertFile"></a-input>
<a-input type="text" v-model="allSetting.webCertFile" placeholder="/root/cert/域名/fullchain.pem" class="red-placeholder"></a-input>
</template>
</a-setting-list-item>
<a-setting-list-item paddings="small">
<template #title>{{ i18n "pages.settings.privateKeyPath"}}</template>
<template #description>{{ i18n "pages.settings.privateKeyPathDesc"}}</template>
<template #control>
<a-input type="text" v-model="allSetting.webKeyFile"></a-input>
<a-input type="text" v-model="allSetting.webKeyFile" placeholder="/root/cert/域名/privkey.pem" class="red-placeholder"></a-input>
</template>
</a-setting-list-item>
</a-collapse-panel>
@@ -146,4 +152,4 @@
</a-setting-list-item>
</a-collapse-panel>
</a-collapse>
{{end}}
{{end}}
+1 -1
View File
@@ -47,7 +47,7 @@ var defaultValueMap = map[string]string{
"tgBotBackup": "false",
"tgBotLoginNotify": "true",
"tgCpu": "80",
"tgLang": "en-US",
"tgLang": "zh-CN",
"twoFactorEnable": "false",
"twoFactorToken": "",
"subEnable": "false",
+4
View File
@@ -81,6 +81,7 @@
"xray" = "Xray Configs"
"logout" = "Log Out"
"link" = "Manage"
"navigation" = "navigation"
[pages.login]
"hello" = "Hello"
@@ -449,6 +450,9 @@
"statsOutboundDownlink" = "Outbound Download Statistics"
"statsOutboundDownlinkDesc" = "Enables the statistics collection for downstream traffic of all outbound proxies."
[pages.navigation]
"title" = "navigation"
[pages.xray.rules]
"first" = "First"
"last" = "Last"
+49 -27
View File
@@ -28,7 +28,7 @@
"edit" = "编辑"
"delete" = "删除"
"reset" = "重置"
"noData" = "无数据"
"noData" = "无数据"
"copySuccess" = "复制成功"
"sure" = "确定"
"encryption" = "加密"
@@ -54,17 +54,18 @@
"install" = "安装"
"clients" = "客户端"
"usage" = "使用情况"
"secretToken" = "安全密钥"
"twoFactorCode" = "代码"
"remained" = "剩余"
"security" = "安全"
"secAlertTitle" = "安全警报"
"secAlertSsl" = "此连接不安全在激活 TLS 进行数据保护之前,请勿输入敏感信息。"
"secAlertConf" = "某些设置易受攻击建议加强安全协议以防止潜在漏洞。"
"secAlertSSL" = "面板缺少安全连接请安装 TLS 证书以保护数据安全。"
"secAlertPanelPort" = "面板默认端口存在安全风险请配置随机端口或特定端口。"
"secAlertPanelURI" = "面板默认 URI 路径不安全请配置复杂的 URI 路径。"
"secAlertSubURI" = "订阅默认 URI 路径不安全请配置复杂的 URI 路径。"
"secAlertSubJsonURI" = "订阅 JSON 默认 URI 路径不安全请配置复杂的 URI 路径。"
"secAlertSsl" = "此连接不安全在激活 TLS 进行数据保护之前,请勿输入敏感信息。"
"secAlertConf" = "某些设置易受攻击建议加强安全协议以防止潜在漏洞。"
"secAlertSSL" = "面板缺少安全连接请安装 TLS 证书以保护数据安全。"
"secAlertPanelPort" = "面板默认端口存在安全风险请配置随机端口或特定端口。"
"secAlertPanelURI" = "面板默认 URI 路径不安全请配置复杂的 URI 路径。"
"secAlertSubURI" = "订阅默认 URI 路径不安全请配置复杂的 URI 路径。"
"secAlertSubJsonURI" = "订阅 JSON 默认 URI 路径不安全请配置复杂的 URI 路径。"
"emptyDnsDesc" = "未添加DNS服务器。"
"emptyFakeDnsDesc" = "未添加Fake DNS服务器。"
"emptyBalancersDesc" = "未添加负载均衡器。"
@@ -74,13 +75,14 @@
[menu]
"theme" = "主题"
"dark" = "暗色"
"ultraDark" = "超暗色"
"ultraDark" = "色"
"dashboard" = "系统状态"
"inbounds" = "入站列表"
"settings" = "面板设置"
"xray" = "Xray 设置"
"xray" = "Xray设置"
"logout" = "退出登录"
"link" = "管理"
"navigation" = "实用导航"
[pages.login]
"hello" = "你好"
@@ -102,6 +104,7 @@
"swap" = "交换分区"
"storage" = "存储"
"memory" = "内存"
"hard" = "磁盘"
"threads" = "线程"
"xrayStatus" = "Xray"
"stopXray" = "停止"
@@ -138,7 +141,7 @@
"dontRefresh" = "安装中,请勿刷新此页面"
"logs" = "日志"
"config" = "配置"
"backup" = "备份"
"backup" = "备份和恢复"
"backupTitle" = "备份和恢复数据库"
"exportDatabase" = "备份"
"exportDatabaseDesc" = "点击下载包含当前数据库备份的 .db 文件到您的设备。"
@@ -170,6 +173,8 @@
"generalActions" = "通用操作"
"autoRefresh" = "自动刷新"
"autoRefreshInterval" = "间隔"
"create" = "添加"
"update" = "修改"
"modifyInbound" = "修改入站"
"deleteInbound" = "删除入站"
"deleteInboundContent" = "确定要删除入站吗?"
@@ -191,7 +196,7 @@
"publicKey" = "公钥"
"privatekey" = "私钥"
"clickOnQRcode" = "点击二维码复制"
"client" = "客户"
"client" = "客户/用户"
"export" = "导出链接"
"clone" = "克隆"
"cloneInbound" = "克隆"
@@ -210,14 +215,14 @@
"delDepletedClientsTitle" = "删除流量耗尽的客户端"
"delDepletedClientsContent" = "确定要删除所有流量耗尽的客户端吗?"
"email" = "电子邮件"
"emailDesc" = "电子邮件必须完全唯一"
"emailDesc" = "电子邮件必须确保唯一"
"IPLimit" = "IP 限制"
"IPLimitDesc" = "如果数量超过设置值,则禁用入站流量。(0 = 禁用)"
"IPLimitlog" = "IP 日志"
"IPLimitlogDesc" = "IP 历史日志(要启用被禁用的入站流量,请清除日志)"
"IPLimitlogclear" = "清除日志"
"setDefaultCert" = "从面板设置证书"
"telegramDesc" = "请提供Telegram聊天ID。(在机器人中使用'/id'命令)或(@userinfobot"
"telegramDesc" = "请提供Telegram聊天ID。(在机器人中使用'/id'命令或跟@userinfobot机器人对话获取)"
"subscriptionDesc" = "要找到你的订阅 URL,请导航到“详细信息”。此外,你可以为多个客户端使用相同的名称。"
"info" = "信息"
"same" = "相同"
@@ -239,7 +244,7 @@
"prefix" = "前缀"
"postfix" = "后缀"
"delayedStart" = "首次使用后开始"
"expireDays" = "期间"
"expireDays" = "到期天数/期间"
"days" = "天"
"renew" = "自动续订"
"renewDesc" = "到期后自动续订。(0 = 禁用)(单位: 天)"
@@ -289,7 +294,7 @@
"resetDefaultConfig" = "重置为默认配置"
"panelSettings" = "常规"
"securitySettings" = "安全设定"
"TGBotSettings" = "Telegram 机器人配置"
"TGBotSettings" = "Telegram机器人配置"
"panelListeningIP" = "面板监听 IP"
"panelListeningIPDesc" = "默认留空监听所有 IP"
"panelListeningDomain" = "面板监听域名"
@@ -297,10 +302,12 @@
"panelPort" = "面板监听端口"
"panelPortDesc" = "重启面板生效"
"publicKeyPath" = "面板证书公钥文件路径"
"publicKeyPathDesc" = "填写一个 '/' 开头的绝对路径"
"DefaultpublicKeyPath" = "/root/.acme.sh/域名_ecc/域名.cer"
"publicKeyPathDesc" = "填写一个 '/' 开头的绝对路径,〔acme方式〕请自行在填入时修改域名"
"privateKeyPath" = "面板证书密钥文件路径"
"privateKeyPathDesc" = "填写一个 '/' 开头的绝对路径"
"panelUrlPath" = "面板 url 根路径"
"DefaultprivateKeyPath" = "/root/.acme.sh/域名_ecc/域名.key"
"privateKeyPathDesc" = "填写一个 '/' 开头的绝对路径,〔acme方式〕请自行在填入时修改域名"
"panelUrlPath" = "面板登录访问路径"
"panelUrlPathDesc" = "必须以 '/' 开头,以 '/' 结尾"
"pageSize" = "分页大小"
"pageSizeDesc" = "定义入站表的页面大小。设置 0 表示禁用"
@@ -316,7 +323,7 @@
"telegramBotEnable" = "启用 Telegram 机器人"
"telegramBotEnableDesc" = "启用 Telegram 机器人功能"
"telegramToken" = "Telegram 机器人令牌(token"
"telegramTokenDesc" = " '@BotFather' 获取的 Telegram 机器人令牌"
"telegramTokenDesc" = " '@BotFather' 对话获取的 Telegram 机器人令牌"
"telegramProxy" = "SOCKS5 Proxy"
"telegramProxyDesc" = "启用 SOCKS5 代理连接到 Telegram(根据指南调整设置)"
"telegramAPIServer" = "Telegram API Server"
@@ -449,13 +456,16 @@
"statsOutboundDownlink" = "出站下载统计"
"statsOutboundDownlinkDesc" = "启用所有出站代理的下行流量统计收集。"
[pages.navigation]
"title" = "实用导航"
[pages.xray.rules]
"first" = "置顶"
"last" = "置底"
"up" = "向上"
"down" = "向下"
"source" = "来源"
"dest" = "目地址"
"dest" = "目地址"
"inbound" = "入站"
"outbound" = "出站"
"balancer" = "负载均衡"
@@ -463,6 +473,18 @@
"add" = "添加规则"
"edit" = "编辑规则"
"useComma" = "逗号分隔的项目"
"DomainMatcher" = "域匹配类型"
"SourceIPs" = "源IP"
"SourcePort" = "源端口"
"Network" = "网络类型"
"Protocol" = "传输协议"
"Attributes" = "属性"
"Domain" = "域地址"
"User" = "用户"
"Port" = "端口"
"InboundTag" = "入站 Tag"
"OutboundTag" = "出站 Tag"
"BalancerTag" = "负载均衡 Tag"
[pages.xray.outbound]
"addOutbound" = "添加出站"
@@ -583,7 +605,7 @@
[tgbot.commands]
"unknown" = "❗ 未知命令"
"pleaseChoose" = "👇 请选择\r\n"
"pleaseChoose" = "👇请〔按照需求〕选择下方按钮 \r\n"
"help" = "🤖 欢迎使用本机器人!它旨在为您提供来自服务器的特定数据,并允许您进行必要的修改。\r\n\r\n"
"start" = "👋 你好,<i>{{ .Firstname }}</i>。\r\n"
"welcome" = "🤖 欢迎来到 <b>{{ .Hostname }}</b> 管理机器人。\r\n"
@@ -610,7 +632,7 @@
"report" = "🕰 定时报告:{{ .RunTime }}\r\n"
"datetime" = "⏰ 日期时间:{{ .DateTime }}\r\n"
"hostname" = "💻 主机名:{{ .Hostname }}\r\n"
"version" = "🚀 X-UI 版本:{{ .Version }}\r\n"
"version" = "🚀 3X-UI 版本:{{ .Version }}\r\n"
"xrayVersion" = "📡 Xray 版本: {{ .XrayVersion }}\r\n"
"ipv6" = "🌐 IPv6{{ .IPv6 }}\r\n"
"ipv4" = "🌐 IPv4{{ .IPv4 }}\r\n"
@@ -633,7 +655,7 @@
"active" = "💡 激活:{{ .Enable }}\r\n"
"enabled" = "🚨 已启用:{{ .Enable }}\r\n"
"online" = "🌐 连接状态:{{ .Status }}\r\n"
"email" = "📧 邮箱:{{ .Email }}\r\n"
"email" = "📧 邮箱(用户){{ .Email }}\r\n"
"upload" = "🔼 上传↑:{{ .Upload }}\r\n"
"download" = "🔽 下载↓:{{ .Download }}\r\n"
"total" = "📊 总计:{{ .UpDown }} / {{ .Total }}\r\n"
@@ -676,12 +698,12 @@
"confirmRemoveTGUser" = "✅ 确认移除 Telegram 用户?"
"confirmToggle" = "✅ 确认启用/禁用用户?"
"dbBackup" = "获取数据库备份"
"serverUsage" = "服务器使用情况"
"serverUsage" = "服务器状态"
"getInbounds" = "获取入站信息"
"depleteSoon" = "即将耗尽"
"clientUsage" = "获取使用情况"
"onlines" = "在线客户端"
"commands" = "命令"
"commands" = "常用命令"
"refresh" = "🔄 刷新"
"clearIPs" = "❌ 清除 IP"
"removeTGUser" = "❌ 移除 Telegram 用户"
@@ -693,7 +715,7 @@
"ipLimit" = "🔢 IP 限制"
"setTGUser" = "👤 设置 Telegram 用户"
"toggle" = "🔘 启用/禁用"
"custom" = "🔢 风俗"
"custom" = "🔢 自定义输入"
"confirmNumber" = "✅ 确认: {{ .Num }}"
"confirmNumberAdd" = "✅ 确认添加:{{ .Num }}"
"limitTraffic" = "🚧 流量限制"
+69
View File
@@ -42,6 +42,9 @@ var i18nFS embed.FS
var startTime = time.Now()
// 预定义 IPv4 私网和回环网段
var privateIPv4Nets []*net.IPNet
type wrapAssetsFS struct {
embed.FS
}
@@ -331,6 +334,12 @@ func (s *Server) Start() (err error) {
if err != nil {
return err
}
if certFile == "" || keyFile == "" {
// 如果没有证书,强制检查 listen 是否内部 IP,否则回退到本地
if !isInternalIP(listen) {
listen = fallbackToLocalhost(listen)
}
}
listenAddr := net.JoinHostPort(listen, strconv.Itoa(port))
listener, err := net.Listen("tcp", listenAddr)
if err != nil {
@@ -400,3 +409,63 @@ func (s *Server) GetCtx() context.Context {
func (s *Server) GetCron() *cron.Cron {
return s.cron
}
// isInternalIP 判断是否为私网或回环IP(支持IPv4和IPv6)
func isInternalIP(ipStr string) bool {
ip := net.ParseIP(ipStr)
if ip == nil {
return false
}
if ip4 := ip.To4(); ip4 != nil {
// IPv4 判断是否在私网/回环网段内
for _, privateNet := range privateIPv4Nets {
if privateNet.Contains(ip4) {
return true
}
}
return false
}
// IPv6 判断回环或链路本地地址
if ip.IsLoopback() || ip.IsLinkLocalUnicast() {
return true
}
// 判断 IPv6 fc00::/7 私网地址段
if ip[0]&0xfe == 0xfc {
return true
}
return false
}
// fallbackToLocalhost 根据传入地址返回对应的本地回环地址
func fallbackToLocalhost(listen string) string {
ip := net.ParseIP(listen)
if ip == nil {
// 无法解析则默认回退 IPv4 回环
return "127.0.0.1"
}
if ip.To4() != nil {
// IPv4 回退 IPv4 回环
return "127.0.0.1"
}
// IPv6 回退 IPv6 回环
return "::1"
}
func init() {
for _, cidr := range []string{
"10.0.0.0/8", // A类私网
"172.16.0.0/12", // B类私网
"192.168.0.0/16", // C类私网
"100.64.0.0/10", // CGNAT地址段
"127.0.0.0/8", // 回环
} {
_, netw, err := net.ParseCIDR(cidr)
if err == nil {
privateIPv4Nets = append(privateIPv4Nets, netw)
}
}
}