mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-01-11 01:25:11 +08:00
feat: Add support for Mux SSL mode and update related settings
- Introduced a new SSL mode "Mux" in the settings, allowing for HTTP to HTTPS redirection. - Updated the `SSL` field in the `SettingUpdate` struct to include "Mux" as a valid option. - Modified the server logic to handle Mux connections, including certificate management and HTTP redirection. - Updated frontend components to reflect the new SSL options and improved user guidance in multiple languages.
This commit is contained in:
parent
4e7b654090
commit
1112d49d2d
17 changed files with 92 additions and 26 deletions
|
|
@ -64,7 +64,7 @@ type SettingUpdate struct {
|
|||
type SSLUpdate struct {
|
||||
SSLType string `json:"sslType" validate:"required,oneof=self select import import-paste import-local"`
|
||||
Domain string `json:"domain"`
|
||||
SSL string `json:"ssl" validate:"required,oneof=Enable Disable"`
|
||||
SSL string `json:"ssl" validate:"required,oneof=Enable Disable Mux"`
|
||||
Cert string `json:"cert"`
|
||||
Key string `json:"key"`
|
||||
SSLID uint `json:"sslID"`
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ const (
|
|||
|
||||
StatusEnable = "Enable"
|
||||
StatusDisable = "Disable"
|
||||
StatusMux = "Mux"
|
||||
|
||||
StatusInstalling = "Installing"
|
||||
StatusNormal = "Normal"
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ require (
|
|||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/soheilhy/cmux v0.1.5 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.11.0 // indirect
|
||||
github.com/spf13/cast v1.6.0 // indirect
|
||||
|
|
|
|||
|
|
@ -250,6 +250,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ
|
|||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
|
||||
github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js=
|
||||
github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
|
||||
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
||||
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||
|
|
@ -342,6 +344,7 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn
|
|||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
|
|
@ -363,6 +366,7 @@ golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
|
|
|||
|
|
@ -4,6 +4,11 @@ import (
|
|||
"crypto/tls"
|
||||
"encoding/gob"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/core/init/auth"
|
||||
"github.com/1Panel-dev/1Panel/core/init/db"
|
||||
"github.com/1Panel-dev/1Panel/core/init/geo"
|
||||
|
|
@ -12,10 +17,7 @@ import (
|
|||
"github.com/1Panel-dev/1Panel/core/init/proxy"
|
||||
"github.com/1Panel-dev/1Panel/core/init/run"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"github.com/soheilhy/cmux"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/core/constant"
|
||||
"github.com/1Panel-dev/1Panel/core/global"
|
||||
|
|
@ -99,10 +101,64 @@ func Start() {
|
|||
if err := server.ServeTLS(tcpKeepAliveListener{ln.(*net.TCPListener)}, "", ""); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
} else if global.CONF.Conn.SSL == constant.StatusMux {
|
||||
certPath := path.Join(global.CONF.Base.InstallDir, "1panel/secret/server.crt")
|
||||
keyPath := path.Join(global.CONF.Base.InstallDir, "1panel/secret/server.key")
|
||||
certificate, err := os.ReadFile(certPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
key, err := os.ReadFile(keyPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
cert, err := tls.X509KeyPair(certificate, key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
constant.CertStore.Store(&cert)
|
||||
|
||||
server.TLSConfig = &tls.Config{
|
||||
GetCertificate: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
return constant.CertStore.Load().(*tls.Certificate), nil
|
||||
},
|
||||
}
|
||||
|
||||
global.LOG.Infof("listen at mux (http/https)://%s:%s [%s]", global.CONF.Conn.BindAddress, global.CONF.Conn.Port, tcpItem)
|
||||
|
||||
m := cmux.New(ln)
|
||||
|
||||
httpsL := m.Match(cmux.TLS())
|
||||
httpL := m.Match(cmux.Any())
|
||||
|
||||
go func() {
|
||||
if err := server.Serve(tls.NewListener(httpsL, server.TLSConfig)); err != nil {
|
||||
global.LOG.Errorf("HTTPS Serve Error: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
redirectServer := &http.Server{
|
||||
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
target := "https://" + r.Host + r.RequestURI
|
||||
http.Redirect(w, r, target, http.StatusTemporaryRedirect)
|
||||
}),
|
||||
}
|
||||
if err := redirectServer.Serve(httpL); err != nil {
|
||||
global.LOG.Errorf("HTTP Redirect Serve Error: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
if err := m.Serve(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
} else {
|
||||
global.LOG.Infof("listen at http://%s:%s [%s]", global.CONF.Conn.BindAddress, global.CONF.Conn.Port, tcpItem)
|
||||
if err := server.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1995,7 +1995,7 @@ const message = {
|
|||
error444: 'Connection Closed',
|
||||
error500: 'Internal Server Error',
|
||||
|
||||
https: 'Setting up HTTPS protocol access for the panel can enhance the security of panel access.',
|
||||
https: 'Setting up HTTPS for the panel improves security.\nStrict mode blocks non-HTTPS access.\nMux redirects HTTP to HTTPS but may reduce performance slightly.',
|
||||
certType: 'Certificate type',
|
||||
selfSigned: 'Self signed',
|
||||
selfSignedHelper: `Browsers may not trust self-signed certificates and may display security warnings.`,
|
||||
|
|
|
|||
|
|
@ -2009,7 +2009,7 @@ const message = {
|
|||
error416: 'Rango no satisfactorio',
|
||||
error444: 'Conexión cerrada',
|
||||
error500: 'Error interno del servidor',
|
||||
https: 'Configurar acceso al panel mediante protocolo HTTPS puede mejorar la seguridad del acceso.',
|
||||
https: 'Configurar HTTPS para el panel mejora la seguridad.\nEl modo Strict bloquea el acceso sin HTTPS.\nMux redirige HTTP a HTTPS, pero puede reducir ligeramente el rendimiento.',
|
||||
certType: 'Tipo de certificado',
|
||||
selfSigned: 'Autofirmado',
|
||||
selfSignedHelper:
|
||||
|
|
|
|||
|
|
@ -1921,7 +1921,7 @@ const message = {
|
|||
error444: '接続が閉じた',
|
||||
error500: 'サーバーエラー',
|
||||
|
||||
https: 'パネル用のHTTPSプロトコルアクセスをセットアップすると、パネルアクセスのセキュリティが強化されます。',
|
||||
https: 'パネルに HTTPS を設定すると安全性が向上します。\nStrict モードは HTTPS 以外のアクセスを遮断します。\nMux は HTTP を HTTPS へリダイレクトしますが、わずかに性能が低下する場合があります。',
|
||||
certType: '証明書の種類',
|
||||
selfSigned: '自己署名',
|
||||
selfSignedHelper: `ブラウザは、自己署名の証明書を信頼していない場合があり、セキュリティ警告を表示する場合があります。`,
|
||||
|
|
|
|||
|
|
@ -1890,7 +1890,7 @@ const message = {
|
|||
error444: '연결 닫힘',
|
||||
error500: '서버 오류',
|
||||
|
||||
https: '패널의 HTTPS 프로토콜 접근 설정은 패널 접근 보안을 강화할 수 있습니다.',
|
||||
https: '패널에 HTTPS를 설정하면 보안이 향상됩니다.\nStrict 모드는 HTTPS가 아닌 접근을 차단합니다.\nMux는 HTTP를 HTTPS로 리다이렉트하지만 성능이 약간 저하될 수 있습니다.',
|
||||
certType: '인증서 유형',
|
||||
selfSigned: '자가 서명',
|
||||
selfSignedHelper: '자가 서명 인증서는 브라우저에서 신뢰하지 않을 수 있으며 보안 경고가 표시될 수 있습니다.',
|
||||
|
|
|
|||
|
|
@ -1977,7 +1977,7 @@ const message = {
|
|||
error444: 'Sambungan ditutup',
|
||||
error500: 'Ralat Pelayan',
|
||||
|
||||
https: 'Menetapkan protokol akses HTTPS untuk panel boleh meningkatkan keselamatan akses panel.',
|
||||
https: 'Menetapkan HTTPS untuk panel meningkatkan keselamatan.\nMod Strict menyekat akses bukan HTTPS.\nMux mengalih hala HTTP ke HTTPS tetapi mungkin mengurangkan sedikit prestasi.',
|
||||
certType: 'Jenis sijil',
|
||||
selfSigned: 'Diterbitkan sendiri',
|
||||
selfSignedHelper:
|
||||
|
|
|
|||
|
|
@ -1965,7 +1965,7 @@ const message = {
|
|||
error444: 'Conexão fechada',
|
||||
error500: 'Erro no servidor',
|
||||
|
||||
https: 'Configurar o acesso via protocolo HTTPS para o painel pode melhorar a segurança do acesso ao painel.',
|
||||
https: 'Configurar HTTPS para o painel melhora a segurança.\nO modo Strict bloqueia acesso sem HTTPS.\nMux redireciona HTTP para HTTPS, mas pode reduzir levemente o desempenho.',
|
||||
certType: 'Tipo de certificado',
|
||||
selfSigned: 'Autoassinado',
|
||||
selfSignedHelper:
|
||||
|
|
|
|||
|
|
@ -1963,7 +1963,7 @@ const message = {
|
|||
error444: 'Соединение закрыто',
|
||||
error500: 'Ошибка сервера',
|
||||
|
||||
https: 'Настройка доступа по протоколу HTTPS для панели может повысить безопасность доступа к панели.',
|
||||
https: 'Настройка HTTPS для панели повышает безопасность.\nРежим Strict блокирует доступ без HTTPS.\nMux перенаправляет HTTP на HTTPS, но может немного снизить производительность.',
|
||||
certType: 'Тип сертификата',
|
||||
selfSigned: 'Самоподписанный',
|
||||
selfSignedHelper:
|
||||
|
|
|
|||
|
|
@ -2018,7 +2018,7 @@ const message = {
|
|||
error416: 'Aralık Karşılanamadı',
|
||||
error444: 'Bağlantı Kapalı',
|
||||
error500: 'Dahili Sunucu Hatası',
|
||||
https: 'Panel için HTTPS protokolü erişimini ayarlamak, panel erişiminin güvenliğini artırabilir.',
|
||||
https: 'Panel için HTTPS kurmak güvenliği artırır.\nStrict modu HTTPS olmayan erişimi engeller.\nMux HTTP’yi HTTPS’e yönlendirir, ancak performansı biraz düşürebilir.',
|
||||
certType: 'Sertifika türü',
|
||||
selfSigned: 'Kendi kendine imzalı',
|
||||
selfSignedHelper:
|
||||
|
|
|
|||
|
|
@ -1944,7 +1944,7 @@ const message = {
|
|||
error444: '連線已關閉',
|
||||
error500: '內部伺服器錯誤',
|
||||
|
||||
https: '為面板設定 https 協議訪問,提升面板訪問安全性',
|
||||
https: '為面板設定 HTTPS 可提升安全性。\nStrict 模式會阻擋非 HTTPS 連線。\nMux 會將 HTTP 重新導向到 HTTPS,但可能稍微降低效能。',
|
||||
certType: '證書類型',
|
||||
selfSigned: '自簽名',
|
||||
selfSignedHelper: '自簽證書,不被瀏覽器信任,顯示不安全是正常現象',
|
||||
|
|
|
|||
|
|
@ -1943,7 +1943,7 @@ const message = {
|
|||
error444: '连接被关闭',
|
||||
error500: '内部错误',
|
||||
|
||||
https: '为面板设置 https 协议访问,提升面板访问安全性',
|
||||
https: '为面板设置https协议访问可提升面板访问安全性 \n Strict模式下非HTTPS流量无法连接面板\nMux模式会将 HTTP重定向到 HTTPS, 但可能会降低少许性能',
|
||||
certType: '证书类型',
|
||||
selfSigned: '自签名',
|
||||
selfSignedHelper: '自签证书,不被浏览器信任,显示不安全是正常现象',
|
||||
|
|
|
|||
|
|
@ -104,14 +104,13 @@
|
|||
</el-form-item>
|
||||
|
||||
<el-form-item :label="$t('setting.panelSSL')" prop="ssl">
|
||||
<el-switch
|
||||
@change="handleSSL"
|
||||
v-model="form.ssl"
|
||||
active-value="Enable"
|
||||
inactive-value="Disable"
|
||||
/>
|
||||
<el-radio-group v-model="form.ssl" @change="handleSSL">
|
||||
<el-radio value="Disable">{{ $t('setting.sslDisable') }}</el-radio>
|
||||
<el-radio value="Enable">{{ $t('commons.button.enable') }} (Strict)</el-radio>
|
||||
<el-radio value="Mux">{{ $t('commons.button.enable') }} (Mux)</el-radio>
|
||||
</el-radio-group>
|
||||
<span class="input-help">{{ $t('setting.https') }}</span>
|
||||
<div v-if="form.ssl === 'Enable' && sslInfo">
|
||||
<div v-if="form.ssl !== 'Disable' && sslInfo">
|
||||
<el-tag>{{ $t('setting.domainOrIP') }} {{ sslInfo.domain }}</el-tag>
|
||||
<el-tag style="margin-left: 5px">
|
||||
{{ $t('setting.timeOut') }} {{ sslInfo.timeout }}
|
||||
|
|
@ -210,6 +209,7 @@ const mfaRef = ref();
|
|||
const responseRef = ref();
|
||||
|
||||
const sslRef = ref();
|
||||
const lastSSL = ref('Disable');
|
||||
const sslInfo = ref<Setting.SSLInfo>();
|
||||
const domainRef = ref();
|
||||
const allowIPsRef = ref();
|
||||
|
|
@ -243,8 +243,9 @@ const search = async () => {
|
|||
form.ipv6 = res.data.ipv6;
|
||||
form.bindAddress = res.data.bindAddress;
|
||||
form.ssl = res.data.ssl;
|
||||
lastSSL.value = form.ssl;
|
||||
form.sslType = res.data.sslType;
|
||||
if (form.ssl === 'Enable') {
|
||||
if (form.ssl !== 'Disable') {
|
||||
loadInfo();
|
||||
}
|
||||
form.securityEntrance = res.data.securityEntrance;
|
||||
|
|
@ -326,7 +327,7 @@ const onChangeAllowIPs = () => {
|
|||
allowIPsRef.value.acceptParams({ allowIPs: form.allowIPs });
|
||||
};
|
||||
const handleSSL = async () => {
|
||||
if (form.ssl === 'Enable') {
|
||||
if (form.ssl !== 'Disable') {
|
||||
let params = {
|
||||
ssl: form.ssl,
|
||||
sslType: form.sslType,
|
||||
|
|
@ -343,6 +344,7 @@ const handleSSL = async () => {
|
|||
.then(async () => {
|
||||
await updateSSL({ ssl: 'Disable', domain: '', sslType: form.sslType, key: '', cert: '', sslID: 0 });
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
lastSSL.value = 'Disable';
|
||||
let href = window.location.href;
|
||||
globalStore.isLogin = false;
|
||||
let address = href.split('://')[1];
|
||||
|
|
@ -356,7 +358,7 @@ const handleSSL = async () => {
|
|||
}, 1000);
|
||||
})
|
||||
.catch(() => {
|
||||
form.ssl = 'Enable';
|
||||
form.ssl = lastSSL.value;
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -158,10 +158,12 @@ const sslList = ref();
|
|||
const itemSSL = ref();
|
||||
|
||||
interface DialogProps {
|
||||
ssl: string;
|
||||
sslType: string;
|
||||
sslInfo?: Setting.SSLInfo;
|
||||
}
|
||||
const acceptParams = async (params: DialogProps): Promise<void> => {
|
||||
form.ssl = params.ssl;
|
||||
if (params.sslType.indexOf('-') !== -1) {
|
||||
form.sslType = 'import';
|
||||
form.itemSSLType = params.sslType.split('-')[1];
|
||||
|
|
@ -232,7 +234,7 @@ const onSaveSSL = async (formEl: FormInstance | undefined) => {
|
|||
itemType = form.itemSSLType === 'paste' ? 'import-paste' : 'import-local';
|
||||
}
|
||||
let param = {
|
||||
ssl: 'Enable',
|
||||
ssl: form.ssl,
|
||||
sslType: itemType,
|
||||
domain: '',
|
||||
sslID: form.sslID,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue