feat: Optimize reverse proxy handling for applications with HTTPS ports. (#12181)

This commit is contained in:
CityFun
2026-03-16 08:07:51 +00:00
committed by GitHub
parent 4375722aef
commit 2dfe5096f0
5 changed files with 71 additions and 17 deletions
+2 -2
View File
@@ -113,8 +113,8 @@ var catalog = map[string]Meta{
EnvKey: "MINIMAX_API_KEY",
Enabled: true,
Models: []Model{
{ID: "minimax/MiniMax-M2.1", Name: "MiniMax M2.1"},
{ID: "minimax/MiniMax-M2.1-lightning", Name: "MiniMax M2.1 Lightning"},
{ID: "minimax/MiniMax-M2.5", Name: "MiniMax M2.5"},
{ID: "minimax/MiniMax-M2.5-highspeed", Name: "MiniMax M2.5 highspeed"},
},
},
"kimi": {
+2 -10
View File
@@ -114,7 +114,7 @@ func (w WebsiteService) OperateProxy(req request.WebsiteProxyConfig) (err error)
err = errors.New("invalid proxy config, no location found")
return
}
location.UpdateDirective("proxy_pass", []string{req.ProxyPass})
applyLocationProxyPass(location, req.ProxyPass, &req.SNI, req.ProxySSLName)
location.UpdateDirective("proxy_set_header", []string{"Host", req.ProxyHost})
location.ChangePath(req.Modifier, req.Match)
// Server Cache Settings
@@ -143,15 +143,7 @@ func (w WebsiteService) OperateProxy(req request.WebsiteProxyConfig) (err error)
} else {
location.RemoveSubFilter()
}
// SSL Settings
if req.SNI {
location.UpdateDirective("proxy_ssl_server_name", []string{"on"})
if req.ProxySSLName != "" {
location.UpdateDirective("proxy_ssl_name", []string{req.ProxySSLName})
}
} else {
location.UpdateDirective("proxy_ssl_server_name", []string{"off"})
}
// Explicit SNI configuration still takes precedence over the automatic HTTPS upstream default.
// CORS Settings
if req.Cors {
location.UpdateDirective("add_header", []string{"Access-Control-Allow-Origin", req.AllowOrigins, "always"})
+25 -1
View File
@@ -47,6 +47,30 @@ func handleChineseDomain(domain string) (string, error) {
return domain, nil
}
func isHTTPSProxyPass(proxyPass string) bool {
return strings.HasPrefix(strings.ToLower(strings.TrimSpace(proxyPass)), "https://")
}
func applyLocationProxyPass(location *components.Location, proxyPass string, sni *bool, proxySSLName string) {
location.UpdateDirective("proxy_pass", []string{proxyPass})
enableSNI := isHTTPSProxyPass(proxyPass)
if sni != nil {
enableSNI = enableSNI && *sni
}
if enableSNI {
location.UpdateDirective("proxy_ssl_server_name", []string{"on"})
} else {
location.UpdateDirective("proxy_ssl_server_name", []string{"off"})
}
sslName := "$proxy_host"
if proxySSLName != "" {
sslName = proxySSLName
}
location.UpdateDirective("proxy_ssl_name", []string{sslName})
}
func createIndexFile(website *model.Website, runtime *model.Runtime) error {
var (
indexPath string
@@ -122,7 +146,7 @@ func createProxyFile(website *model.Website) error {
return errors.New("error")
}
location.ChangePath("^~", "/")
location.UpdateDirective("proxy_pass", []string{website.Proxy})
applyLocationProxyPass(location, website.Proxy, nil, "")
location.UpdateDirective("proxy_set_header", []string{"Host", "$host"})
if err := nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
return buserr.WithErr("ErrUpdateBuWebsite", err)
@@ -57,7 +57,7 @@
<span class="font-medium">{{ $t('website.sni') }}</span>
<span class="input-help">{{ $t('website.sniHelper') }}</span>
</div>
<el-switch v-model="proxy.sni" size="large" />
<el-switch v-model="proxy.sni" size="large" @change="handleSNIChange" />
</div>
<el-form-item
@@ -237,7 +237,7 @@ import { operateProxyConfig } from '@/api/modules/website';
import { checkNumberRange, Rules } from '@/global/form-rules';
import i18n from '@/lang';
import { FormInstance } from 'element-plus';
import { ref } from 'vue';
import { ref, watch } from 'vue';
import { MsgError, MsgSuccess } from '@/utils/message';
import { Website } from '@/api/interface/website';
import { Units } from '@/global/mimetype';
@@ -258,6 +258,8 @@ const rules = ref({
const open = ref(false);
const loading = ref(false);
const activeTab = ref('basic');
const shouldAutoEnableSNI = ref(false);
const sniTouched = ref(false);
const initData = (): Website.ProxyConfig => ({
id: 0,
@@ -300,6 +302,8 @@ const acceptParams = (proxyParam: Website.ProxyConfig) => {
replaces.value = [];
proxy.value = proxyParam;
activeTab.value = 'basic';
shouldAutoEnableSNI.value = proxy.value.operate === 'create';
sniTouched.value = false;
// Initialize browserCache based on cacheTime value
if (proxy.value.cacheTime > 0) {
@@ -359,6 +363,10 @@ const removeReplace = (index: number) => {
replaces.value.splice(index, 1);
};
const handleSNIChange = () => {
sniTouched.value = true;
};
const getProxyHost = () => {
if (isDomain(proxy.value.proxyAddress)) {
proxy.value.proxyHost = proxy.value.proxyAddress;
@@ -425,6 +433,16 @@ const getProtocolAndHost = (url: string): { protocol: string; host: string } | n
return { protocol: '', host: url };
};
watch(
() => proxy.value.proxyProtocol,
(protocol) => {
if (proxy.value.operate !== 'create' || sniTouched.value || !shouldAutoEnableSNI.value) {
return;
}
proxy.value.sni = protocol === 'https://';
},
);
defineExpose({
acceptParams,
});
@@ -672,11 +672,31 @@ const getAppByService = async (key: string) => {
dbServices.value = res.data;
};
const getProxyTargetFromApp = (app: Pick<App.AppInstalled, 'httpPort' | 'httpsPort'>) => {
if ((app.httpPort ?? 0) > 0) {
return {
protocol: 'http://',
address: `127.0.0.1:${app.httpPort}`,
};
}
if ((app.httpsPort ?? 0) > 0) {
return {
protocol: 'https://',
address: `127.0.0.1:${app.httpsPort}`,
};
}
return {
protocol: 'http://',
address: '',
};
};
const changeInstall = () => {
appInstalls.value.forEach((app) => {
if (app.id === website.value.appInstallId) {
website.value.proxyProtocol = 'http://';
website.value.proxyAddress = '127.0.0.1:' + app.httpPort;
const target = getProxyTargetFromApp(app);
website.value.proxyProtocol = target.protocol;
website.value.proxyAddress = target.address;
}
});
};