1
0
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:
zhengkunwang223 2022-12-28 16:07:43 +08:00 committed by zhengkunwang223
parent 29c8a2180f
commit e2403c9869
12 changed files with 132 additions and 75 deletions

View File

@ -7,7 +7,7 @@
"required": true,
"default": 80,
"envKey": "PANEL_APP_PORT_HTTP",
"disabled": true,
"disabled": true
},
{
"type": "number",

View File

@ -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)
}

View File

@ -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 {

View File

@ -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"`
}

View File

@ -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"`

View File

@ -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
}

View File

@ -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
}

View File

@ -28,4 +28,8 @@ const (
StartWeb = "start"
StopWeb = "stop"
HTTPSOnly = "HTTPSOnly"
HTTPAlso = "HTTPAlso"
HTTPToHTTPS = "HTTPToHTTPS"
)

View File

@ -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)
}

View File

@ -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 {

View File

@ -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表大小',

View File

@ -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;