mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-01-31 14:08:06 +08:00
feat: HTTPS增加配置
This commit is contained in:
parent
29c8a2180f
commit
e2403c9869
@ -7,7 +7,7 @@
|
||||
"required": true,
|
||||
"default": 80,
|
||||
"envKey": "PANEL_APP_PORT_HTTP",
|
||||
"disabled": true,
|
||||
"disabled": true
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
|
@ -256,11 +256,14 @@ func (b *BaseApi) UpdateHTTPSConfig(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
res, err := websiteService.OpWebsiteHTTPS(req)
|
||||
tx, ctx := helper.GetTxAndContext()
|
||||
res, err := websiteService.OpWebsiteHTTPS(ctx, req)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
tx.Commit()
|
||||
helper.SuccessWithData(c, res)
|
||||
}
|
||||
|
||||
|
@ -102,6 +102,7 @@ type WebsiteHTTPSOp struct {
|
||||
Type string `json:"type" validate:"oneof=existed auto manual"`
|
||||
PrivateKey string `json:"privateKey"`
|
||||
Certificate string `json:"certificate"`
|
||||
HttpConfig string `json:"HttpConfig" validate:"oneof=HTTPSOnly HTTPAlso HTTPToHTTPS"`
|
||||
}
|
||||
|
||||
type WebsiteNginxUpdate struct {
|
||||
|
@ -30,6 +30,7 @@ type WebsiteWafConfig struct {
|
||||
}
|
||||
|
||||
type WebsiteHTTPS struct {
|
||||
Enable bool `json:"enable"`
|
||||
SSL model.WebsiteSSL `json:"SSL"`
|
||||
Enable bool `json:"enable"`
|
||||
HttpConfig string `json:"httpConfig"`
|
||||
SSL model.WebsiteSSL `json:"SSL"`
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ type Website struct {
|
||||
Alias string `gorm:"type:varchar(128);not null" json:"alias"`
|
||||
Remark string `gorm:"type:longtext;" json:"remark"`
|
||||
Status string `gorm:"type:varchar(64);not null" json:"status"`
|
||||
HttpConfig string `gorm:"type:varchar(64);not null" json:"httpConfig"`
|
||||
ExpireDate time.Time `json:"expireDate"`
|
||||
AppInstallID uint `gorm:"type:integer" json:"appInstallId"`
|
||||
WebsiteGroupID uint `gorm:"type:integer" json:"webSiteGroupId"`
|
||||
|
@ -44,7 +44,7 @@ type IWebsiteService interface {
|
||||
UpdateNginxConfigByScope(req request.NginxConfigUpdate) error
|
||||
GetWebsiteNginxConfig(websiteId uint) (response.FileInfo, error)
|
||||
GetWebsiteHTTPS(websiteId uint) (response.WebsiteHTTPS, error)
|
||||
OpWebsiteHTTPS(req request.WebsiteHTTPSOp) (response.WebsiteHTTPS, error)
|
||||
OpWebsiteHTTPS(ctx context.Context, req request.WebsiteHTTPSOp) (response.WebsiteHTTPS, error)
|
||||
PreInstallCheck(req request.WebsiteInstallCheckReq) ([]response.WebsitePreInstallCheck, error)
|
||||
GetWafConfig(req request.WebsiteWafReq) (response.WebsiteWafConfig, error)
|
||||
UpdateWafConfig(req request.WebsiteWafUpdate) error
|
||||
@ -472,84 +472,78 @@ func (w WebsiteService) GetWebsiteHTTPS(websiteId uint) (response.WebsiteHTTPS,
|
||||
}
|
||||
res.SSL = websiteSSL
|
||||
res.Enable = true
|
||||
if website.HttpConfig != "" {
|
||||
res.HttpConfig = website.HttpConfig
|
||||
} else {
|
||||
res.HttpConfig = constant.HTTPToHTTPS
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (w WebsiteService) OpWebsiteHTTPS(req request.WebsiteHTTPSOp) (response.WebsiteHTTPS, error) {
|
||||
func (w WebsiteService) OpWebsiteHTTPS(ctx context.Context, req request.WebsiteHTTPSOp) (response.WebsiteHTTPS, error) {
|
||||
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
|
||||
if err != nil {
|
||||
return response.WebsiteHTTPS{}, err
|
||||
}
|
||||
|
||||
var (
|
||||
res response.WebsiteHTTPS
|
||||
websiteSSL model.WebsiteSSL
|
||||
)
|
||||
res.Enable = req.Enable
|
||||
|
||||
if req.Type == constant.SSLExisted {
|
||||
websiteSSL, err = websiteSSLRepo.GetFirst(commonRepo.WithByID(req.WebsiteSSLID))
|
||||
if err != nil {
|
||||
return response.WebsiteHTTPS{}, err
|
||||
if req.Enable {
|
||||
if req.Type == constant.SSLExisted {
|
||||
websiteSSL, err = websiteSSLRepo.GetFirst(commonRepo.WithByID(req.WebsiteSSLID))
|
||||
if err != nil {
|
||||
return response.WebsiteHTTPS{}, err
|
||||
}
|
||||
website.WebsiteSSLID = websiteSSL.ID
|
||||
res.SSL = websiteSSL
|
||||
}
|
||||
website.WebsiteSSLID = websiteSSL.ID
|
||||
if err := websiteRepo.Save(context.TODO(), &website); err != nil {
|
||||
return response.WebsiteHTTPS{}, err
|
||||
}
|
||||
res.SSL = websiteSSL
|
||||
}
|
||||
|
||||
if req.Type == constant.SSLManual {
|
||||
certBlock, _ := pem.Decode([]byte(req.Certificate))
|
||||
cert, err := x509.ParseCertificate(certBlock.Bytes)
|
||||
if err != nil {
|
||||
return response.WebsiteHTTPS{}, err
|
||||
}
|
||||
websiteSSL.ExpireDate = cert.NotAfter
|
||||
websiteSSL.StartDate = cert.NotBefore
|
||||
websiteSSL.Type = cert.Issuer.CommonName
|
||||
websiteSSL.Organization = cert.Issuer.Organization[0]
|
||||
websiteSSL.PrimaryDomain = cert.Subject.CommonName
|
||||
if len(cert.Subject.Names) > 0 {
|
||||
var domains []string
|
||||
for _, name := range cert.Subject.Names {
|
||||
if v, ok := name.Value.(string); ok {
|
||||
if v != cert.Subject.CommonName {
|
||||
domains = append(domains, v)
|
||||
if req.Type == constant.SSLManual {
|
||||
certBlock, _ := pem.Decode([]byte(req.Certificate))
|
||||
cert, err := x509.ParseCertificate(certBlock.Bytes)
|
||||
if err != nil {
|
||||
return response.WebsiteHTTPS{}, err
|
||||
}
|
||||
websiteSSL.ExpireDate = cert.NotAfter
|
||||
websiteSSL.StartDate = cert.NotBefore
|
||||
websiteSSL.Type = cert.Issuer.CommonName
|
||||
websiteSSL.Organization = cert.Issuer.Organization[0]
|
||||
websiteSSL.PrimaryDomain = cert.Subject.CommonName
|
||||
if len(cert.Subject.Names) > 0 {
|
||||
var domains []string
|
||||
for _, name := range cert.Subject.Names {
|
||||
if v, ok := name.Value.(string); ok {
|
||||
if v != cert.Subject.CommonName {
|
||||
domains = append(domains, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(domains) > 0 {
|
||||
websiteSSL.Domains = strings.Join(domains, "")
|
||||
}
|
||||
}
|
||||
if len(domains) > 0 {
|
||||
websiteSSL.Domains = strings.Join(domains, "")
|
||||
}
|
||||
websiteSSL.Provider = constant.Manual
|
||||
websiteSSL.PrivateKey = req.PrivateKey
|
||||
websiteSSL.Pem = req.Certificate
|
||||
res.SSL = websiteSSL
|
||||
}
|
||||
|
||||
websiteSSL.Provider = constant.Manual
|
||||
websiteSSL.PrivateKey = req.PrivateKey
|
||||
websiteSSL.Pem = req.Certificate
|
||||
|
||||
res.SSL = websiteSSL
|
||||
}
|
||||
|
||||
if req.Enable {
|
||||
website.Protocol = constant.ProtocolHTTPS
|
||||
if err := applySSL(website, websiteSSL); err != nil {
|
||||
if err := applySSL(website, websiteSSL, req.HttpConfig); err != nil {
|
||||
return response.WebsiteHTTPS{}, err
|
||||
}
|
||||
website.HttpConfig = req.HttpConfig
|
||||
} else {
|
||||
website.Protocol = constant.ProtocolHTTP
|
||||
website.WebsiteSSLID = 0
|
||||
|
||||
if err := deleteListenAndServerName(website, []int{443}, []string{}); err != nil {
|
||||
return response.WebsiteHTTPS{}, err
|
||||
}
|
||||
|
||||
if err := deleteNginxConfig(constant.NginxScopeServer, getKeysFromStaticFile(dto.SSL), &website); err != nil {
|
||||
return response.WebsiteHTTPS{}, err
|
||||
}
|
||||
}
|
||||
|
||||
tx, ctx := getTxAndContext()
|
||||
if websiteSSL.ID == 0 {
|
||||
if err := websiteSSLRepo.Create(ctx, &websiteSSL); err != nil {
|
||||
return response.WebsiteHTTPS{}, err
|
||||
@ -559,8 +553,6 @@ func (w WebsiteService) OpWebsiteHTTPS(req request.WebsiteHTTPSOp) (response.Web
|
||||
if err := websiteRepo.Save(ctx, &website); err != nil {
|
||||
return response.WebsiteHTTPS{}, err
|
||||
}
|
||||
|
||||
tx.Commit()
|
||||
return res, nil
|
||||
}
|
||||
|
||||
|
@ -298,7 +298,7 @@ func createPemFile(website model.Website, websiteSSL model.WebsiteSSL) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func applySSL(website model.Website, websiteSSL model.WebsiteSSL) error {
|
||||
func applySSL(website model.Website, websiteSSL model.WebsiteSSL, httpConfig string) error {
|
||||
nginxFull, err := getNginxFull(&website)
|
||||
if err != nil {
|
||||
return nil
|
||||
@ -306,10 +306,22 @@ func applySSL(website model.Website, websiteSSL model.WebsiteSSL) error {
|
||||
config := nginxFull.SiteConfig.Config
|
||||
server := config.FindServers()[0]
|
||||
server.UpdateListen("443", false, "ssl")
|
||||
|
||||
switch httpConfig {
|
||||
case constant.HTTPSOnly:
|
||||
server.RemoveListenByBind("80")
|
||||
server.RemoveDirective("if", []string{"($scheme"})
|
||||
case constant.HTTPToHTTPS:
|
||||
server.UpdateListen("80", false)
|
||||
server.AddHTTP2HTTPS()
|
||||
case constant.HTTPAlso:
|
||||
server.UpdateListen("80", false)
|
||||
server.RemoveDirective("if", []string{"($scheme"})
|
||||
}
|
||||
|
||||
if err := nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := createPemFile(website, websiteSSL); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -325,7 +337,6 @@ func applySSL(website model.Website, websiteSSL model.WebsiteSSL) error {
|
||||
if err := updateNginxConfig(constant.NginxScopeServer, nginxParams, &website); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -28,4 +28,8 @@ const (
|
||||
|
||||
StartWeb = "start"
|
||||
StopWeb = "stop"
|
||||
|
||||
HTTPSOnly = "HTTPSOnly"
|
||||
HTTPAlso = "HTTPAlso"
|
||||
HTTPToHTTPS = "HTTPToHTTPS"
|
||||
)
|
||||
|
@ -242,13 +242,26 @@ func (s *Server) UpdateDirectiveBySecondKey(name string, key string, directive D
|
||||
}
|
||||
|
||||
func (s *Server) RemoveListenByBind(bind string) {
|
||||
index := 0
|
||||
listens := s.Listens
|
||||
var listens []*ServerListen
|
||||
for _, listen := range s.Listens {
|
||||
if listen.Bind != bind || len(listen.Parameters) > 0 {
|
||||
listens[index] = listen
|
||||
index++
|
||||
listens = append(listens, listen)
|
||||
}
|
||||
}
|
||||
s.Listens = listens
|
||||
}
|
||||
|
||||
func (s *Server) AddHTTP2HTTPS() {
|
||||
newDir := Directive{
|
||||
Name: "if",
|
||||
Parameters: []string{"($scheme = http)"},
|
||||
Block: &Block{},
|
||||
}
|
||||
block := &Block{}
|
||||
block.Directives = append(block.Directives, &Directive{
|
||||
Name: "return",
|
||||
Parameters: []string{"301", "https://$host$request_uri"},
|
||||
})
|
||||
newDir.Block = block
|
||||
s.UpdateDirectiveBySecondKey("if", "($scheme", newDir)
|
||||
}
|
||||
|
@ -204,11 +204,13 @@ export namespace Website {
|
||||
type: string;
|
||||
certificate?: string;
|
||||
privateKey?: string;
|
||||
httpConfig: string;
|
||||
}
|
||||
|
||||
export interface HTTPSConfig {
|
||||
enable: boolean;
|
||||
SSL: SSL;
|
||||
httpConfig: string;
|
||||
}
|
||||
|
||||
export interface CheckReq {
|
||||
|
@ -921,6 +921,16 @@ export default {
|
||||
logFoler: '网站日志',
|
||||
sslFolder: '网站证书',
|
||||
enableOrNot: '是否启用',
|
||||
oldSSL: '选择已有证书',
|
||||
manualSSL: '手动导入证书',
|
||||
select: '选择',
|
||||
selectSSL: '选择证书',
|
||||
privateKey: '密钥代码(pem格式)',
|
||||
certificate: '密钥代码(pem格式)',
|
||||
HTTPConfig: 'HTTP选项',
|
||||
HTTPSOnly: '禁止HTTTP',
|
||||
HTTPToHTTPS: '访问HTTP自动跳转到HTTPS',
|
||||
HTTPAlso: 'HTTP可直接访问',
|
||||
},
|
||||
nginx: {
|
||||
serverNamesHashBucketSizeHelper: '服务器名字的hash表大小',
|
||||
|
@ -9,22 +9,29 @@
|
||||
:rules="rules"
|
||||
:loading="loading"
|
||||
>
|
||||
<el-form-item prop="websiteSSLId">
|
||||
<el-form-item prop="enable">
|
||||
<el-checkbox v-model="form.enable">
|
||||
{{ $t('website.enableHTTPS') }}
|
||||
</el-checkbox>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('website.HTTPConfig')" prop="httpConfig">
|
||||
<el-select v-model="form.httpConfig" style="width: 240px">
|
||||
<el-option :label="$t('website.HTTPToHTTPS')" :value="'HTTPToHTTPS'"></el-option>
|
||||
<el-option :label="$t('website.HTTPAlso')" :value="'HTTPAlso'"></el-option>
|
||||
<el-option :label="$t('website.HTTPSOnly')" :value="'HTTPSOnly'"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('website.ssl')" prop="type">
|
||||
<el-select v-model="form.type" @change="changeType()">
|
||||
<el-option :label="'选择已有证书'" :value="'existed'"></el-option>
|
||||
<el-option :label="'手动导入证书'" :value="'manual'"></el-option>
|
||||
<el-select v-model="form.type" @change="changeType(form.type)">
|
||||
<el-option :label="$t('website.oldSSL')" :value="'existed'"></el-option>
|
||||
<el-option :label="$t('website.manualSSL')" :value="'manual'"></el-option>
|
||||
<!-- <el-option :label="'自动生成证书'" :value="'auto'"></el-option> -->
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="' '" prop="websiteSSLId" v-if="form.type === 'existed'">
|
||||
<el-form-item :label="$t('website.select')" prop="websiteSSLId" v-if="form.type === 'existed'">
|
||||
<el-select
|
||||
v-model="form.websiteSSLId"
|
||||
placeholder="选择证书"
|
||||
:placeholder="$t('website.selectSSL')"
|
||||
@change="changeSSl(form.websiteSSLId)"
|
||||
>
|
||||
<el-option
|
||||
@ -36,18 +43,22 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<div v-if="form.type === 'manual'">
|
||||
<el-form-item :label="'密钥代码(pem格式)'" prop="privateKey">
|
||||
<el-form-item :label="$t('website.privateKey')" prop="privateKey">
|
||||
<el-input v-model="form.privateKey" :rows="6" type="textarea" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="'证书代码(pem格式)'" prop="certificate">
|
||||
<el-form-item :label="$t('website.certificate')" prop="certificate">
|
||||
<el-input v-model="form.certificate" :rows="6" type="textarea" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
<el-form-item :label="' '" v-if="websiteSSL && websiteSSL.id > 0">
|
||||
<el-descriptions :column="3" border direction="vertical">
|
||||
<el-descriptions-item label="主域名">{{ websiteSSL.primaryDomain }}</el-descriptions-item>
|
||||
<el-descriptions-item label="备用域名">{{ websiteSSL.otherDomains }}</el-descriptions-item>
|
||||
<el-descriptions-item label="过期时间">
|
||||
<el-descriptions-item :label="$t('website.primaryDomain')">
|
||||
{{ websiteSSL.primaryDomain }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item :label="$t('website.otherDomains')">
|
||||
{{ websiteSSL.otherDomains }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item :label="$t('website.expireDate')">
|
||||
{{ dateFromat(1, 1, websiteSSL.expireDate) }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
@ -87,6 +98,7 @@ let form = reactive({
|
||||
type: 'existed',
|
||||
privateKey: '',
|
||||
certificate: '',
|
||||
httpConfig: 'HTTPToHTTPS',
|
||||
});
|
||||
let loading = ref(false);
|
||||
const ssls = ref();
|
||||
@ -95,11 +107,14 @@ let rules = ref({
|
||||
type: [Rules.requiredSelect],
|
||||
privateKey: [Rules.requiredInput],
|
||||
certificate: [Rules.requiredInput],
|
||||
websiteSSLId: [Rules.requiredSelect],
|
||||
httpConfig: [Rules.requiredSelect],
|
||||
});
|
||||
|
||||
const listSSL = () => {
|
||||
ListSSL({}).then((res) => {
|
||||
ssls.value = res.data;
|
||||
changeSSl(form.websiteSSLId);
|
||||
});
|
||||
};
|
||||
|
||||
@ -110,15 +125,19 @@ const changeSSl = (sslid: number) => {
|
||||
websiteSSL.value = res[0];
|
||||
};
|
||||
|
||||
const changeType = () => {
|
||||
websiteSSL.value = {};
|
||||
form.websiteSSLId = undefined;
|
||||
const changeType = (type: string) => {
|
||||
if (type != 'existed') {
|
||||
websiteSSL.value = {};
|
||||
form.websiteSSLId = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
const get = () => {
|
||||
GetHTTPSConfig(id.value).then((res) => {
|
||||
console.log(res);
|
||||
if (res.data) {
|
||||
form.enable = res.data.enable;
|
||||
form.httpConfig = res.data.httpConfig;
|
||||
}
|
||||
if (res.data?.SSL && res.data?.SSL.id > 0) {
|
||||
form.websiteSSLId = res.data.SSL.id;
|
||||
|
Loading…
x
Reference in New Issue
Block a user