diff --git a/cmd/ace/wire_gen.go b/cmd/ace/wire_gen.go
index 8de64138..634c61b1 100644
--- a/cmd/ace/wire_gen.go
+++ b/cmd/ace/wire_gen.go
@@ -151,7 +151,7 @@ func initWeb() (*app.Web, error) {
return nil, err
}
gormigrate := bootstrap.NewMigrate(db)
- jobs := job.NewJobs(db, logger, settingRepo, certRepo, backupRepo, cacheRepo, taskRepo)
+ jobs := job.NewJobs(config, db, logger, settingRepo, certRepo, certAccountRepo, backupRepo, cacheRepo, taskRepo)
cron, err := bootstrap.NewCron(config, logger, jobs)
if err != nil {
return nil, err
diff --git a/cmd/cli/wire_gen.go b/cmd/cli/wire_gen.go
index 0c012b2f..38e2c589 100644
--- a/cmd/cli/wire_gen.go
+++ b/cmd/cli/wire_gen.go
@@ -68,7 +68,7 @@ func initCli() (*app.Cli, error) {
certAccountRepo := data.NewCertAccountRepo(locale, db, userRepo, logger)
websiteRepo := data.NewWebsiteRepo(locale, db, cacheRepo, databaseRepo, databaseServerRepo, databaseUserRepo, certRepo, certAccountRepo, settingRepo)
backupRepo := data.NewBackupRepo(locale, db, settingRepo, websiteRepo)
- cliService := service.NewCliService(locale, config, db, appRepo, cacheRepo, userRepo, settingRepo, backupRepo, websiteRepo, databaseServerRepo)
+ cliService := service.NewCliService(locale, config, db, appRepo, cacheRepo, userRepo, settingRepo, backupRepo, websiteRepo, databaseServerRepo, certRepo, certAccountRepo)
cli := route.NewCli(locale, cliService)
command := bootstrap.NewCli(locale, cli)
gormigrate := bootstrap.NewMigrate(db)
diff --git a/internal/biz/cert.go b/internal/biz/cert.go
index 94239490..841d8395 100644
--- a/internal/biz/cert.go
+++ b/internal/biz/cert.go
@@ -38,6 +38,7 @@ type CertRepo interface {
Delete(id uint) error
ObtainAuto(id uint) (*acme.Certificate, error)
ObtainManual(id uint) (*acme.Certificate, error)
+ ObtainPanel(account *CertAccount, ips []string) ([]byte, []byte, error)
ObtainSelfSigned(id uint) error
Renew(id uint) (*acme.Certificate, error)
ManualDNS(id uint) ([]acme.DNSRecord, error)
diff --git a/internal/biz/setting.go b/internal/biz/setting.go
index 85b4cd82..700e544a 100644
--- a/internal/biz/setting.go
+++ b/internal/biz/setting.go
@@ -9,6 +9,7 @@ import (
type SettingKey string
const (
+ SettingKeyIP SettingKey = "ip"
SettingKeyName SettingKey = "name"
SettingKeyVersion SettingKey = "version"
SettingKeyChannel SettingKey = "channel"
diff --git a/internal/data/cert.go b/internal/data/cert.go
index ab45e3b5..83b7f273 100644
--- a/internal/data/cert.go
+++ b/internal/data/cert.go
@@ -6,6 +6,7 @@ import (
"fmt"
"log/slog"
"os"
+ "path/filepath"
"slices"
"strings"
"time"
@@ -233,6 +234,21 @@ func (r *certRepo) ObtainManual(id uint) (*acme.Certificate, error) {
return &ssl, nil
}
+func (r *certRepo) ObtainPanel(account *biz.CertAccount, ips []string) ([]byte, []byte, error) {
+ client, err := acme.NewPrivateKeyAccount(account.Email, account.PrivateKey, acme.CALetsEncrypt, nil, r.log)
+ if err != nil {
+ return nil, nil, err
+ }
+ client.UsePanel(ips, filepath.Join(app.Root, "server/nginx/conf/acme.conf"))
+
+ ssl, err := client.ObtainCertificate(context.Background(), ips, acme.KeyEC256)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ return ssl.ChainPEM, ssl.PrivateKey, nil
+}
+
func (r *certRepo) ObtainSelfSigned(id uint) error {
cert, err := r.Get(id)
if err != nil {
diff --git a/internal/job/cert_renew.go b/internal/job/cert_renew.go
index c2c84dbf..9c41982d 100644
--- a/internal/job/cert_renew.go
+++ b/internal/job/cert_renew.go
@@ -2,8 +2,12 @@ package job
import (
"log/slog"
+ "path/filepath"
"time"
+ "github.com/acepanel/panel/pkg/config"
+ "github.com/acepanel/panel/pkg/io"
+ "github.com/acepanel/panel/pkg/systemctl"
"gorm.io/gorm"
"github.com/acepanel/panel/internal/app"
@@ -13,16 +17,22 @@ import (
// CertRenew 证书续签
type CertRenew struct {
- db *gorm.DB
- log *slog.Logger
- certRepo biz.CertRepo
+ conf *config.Config
+ db *gorm.DB
+ log *slog.Logger
+ settingRepo biz.SettingRepo
+ certRepo biz.CertRepo
+ certAccountRepo biz.CertAccountRepo
}
-func NewCertRenew(db *gorm.DB, log *slog.Logger, cert biz.CertRepo) *CertRenew {
+func NewCertRenew(conf *config.Config, db *gorm.DB, log *slog.Logger, setting biz.SettingRepo, cert biz.CertRepo, certAccount biz.CertAccountRepo) *CertRenew {
return &CertRenew{
- db: db,
- log: log,
- certRepo: cert,
+ conf: conf,
+ db: db,
+ log: log,
+ settingRepo: setting,
+ certRepo: cert,
+ certAccountRepo: certAccount,
}
}
@@ -57,4 +67,52 @@ func (r *CertRenew) Run() {
r.log.Warn("[CertRenew] failed to renew cert", slog.Any("err", err))
}
}
+
+ // 面板证书续签
+ if r.conf.HTTP.ACME {
+ decode, err := pkgcert.ParseCert(filepath.Join(app.Root, "panel/storage/cert.pem"))
+ if err != nil {
+ r.log.Warn("[CertRenew] failed to parse panel cert", slog.Any("err", err))
+ return
+ }
+ // 结束时间大于 2 天不续签
+ if time.Until(decode.NotAfter) > 24*2*time.Hour {
+ return
+ }
+
+ ip, err := r.settingRepo.Get(biz.SettingKeyIP)
+ if err != nil || ip == "" {
+ r.log.Warn("[CertRenew] failed to get panel IP", slog.Any("err", err))
+ return
+ }
+
+ var user biz.User
+ if err = r.db.First(&user).Error; err != nil {
+ r.log.Warn("[CertRenew] failed to get a panel user", slog.Any("err", err))
+ return
+ }
+ account, err := r.certAccountRepo.GetDefault(user.ID)
+ if err != nil {
+ r.log.Warn("[CertRenew] failed to get panel ACME account", slog.Any("err", err))
+ return
+ }
+ crt, key, err := r.certRepo.ObtainPanel(account, []string{ip})
+ if err != nil {
+ r.log.Warn("[CertRenew] failed to obtain ACME cert", slog.Any("err", err))
+ return
+ }
+
+ if err = io.Write(filepath.Join(app.Root, "panel/storage/cert.pem"), string(crt), 0644); err != nil {
+ r.log.Warn("[CertRenew] failed to write panel cert", slog.Any("err", err))
+ return
+ }
+ if err = io.Write(filepath.Join(app.Root, "panel/storage/cert.key"), string(key), 0644); err != nil {
+ r.log.Warn("[CertRenew] failed to write panel cert key", slog.Any("err", err))
+ return
+ }
+
+ r.log.Info("[CertRenew] panel cert renewed successfully")
+ _ = systemctl.Restart("panel")
+ }
+
}
diff --git a/internal/job/job.go b/internal/job/job.go
index ce7bfba9..99e1e5d6 100644
--- a/internal/job/job.go
+++ b/internal/job/job.go
@@ -3,6 +3,7 @@ package job
import (
"log/slog"
+ "github.com/acepanel/panel/pkg/config"
"github.com/google/wire"
"github.com/robfig/cron/v3"
"gorm.io/gorm"
@@ -13,24 +14,28 @@ import (
var ProviderSet = wire.NewSet(NewJobs)
type Jobs struct {
- db *gorm.DB
- log *slog.Logger
- setting biz.SettingRepo
- cert biz.CertRepo
- backup biz.BackupRepo
- cache biz.CacheRepo
- task biz.TaskRepo
+ conf *config.Config
+ db *gorm.DB
+ log *slog.Logger
+ setting biz.SettingRepo
+ cert biz.CertRepo
+ certAccount biz.CertAccountRepo
+ backup biz.BackupRepo
+ cache biz.CacheRepo
+ task biz.TaskRepo
}
-func NewJobs(db *gorm.DB, log *slog.Logger, setting biz.SettingRepo, cert biz.CertRepo, backup biz.BackupRepo, cache biz.CacheRepo, task biz.TaskRepo) *Jobs {
+func NewJobs(conf *config.Config, db *gorm.DB, log *slog.Logger, setting biz.SettingRepo, cert biz.CertRepo, certAccount biz.CertAccountRepo, backup biz.BackupRepo, cache biz.CacheRepo, task biz.TaskRepo) *Jobs {
return &Jobs{
- db: db,
- log: log,
- setting: setting,
- cert: cert,
- backup: backup,
- cache: cache,
- task: task,
+ conf: conf,
+ db: db,
+ log: log,
+ setting: setting,
+ cert: cert,
+ certAccount: certAccount,
+ backup: backup,
+ cache: cache,
+ task: task,
}
}
@@ -38,10 +43,9 @@ func (r *Jobs) Register(c *cron.Cron) error {
if _, err := c.AddJob("* * * * *", NewMonitoring(r.db, r.log, r.setting)); err != nil {
return err
}
- if _, err := c.AddJob("0 4 * * *", NewCertRenew(r.db, r.log, r.cert)); err != nil {
+ if _, err := c.AddJob("0 4 * * *", NewCertRenew(r.conf, r.db, r.log, r.setting, r.cert, r.certAccount)); err != nil {
return err
}
-
if _, err := c.AddJob("0 2 * * *", NewPanelTask(r.db, r.log, r.backup, r.cache, r.task, r.setting)); err != nil {
return err
}
diff --git a/internal/service/cli.go b/internal/service/cli.go
index ef8a9862..2653a1aa 100644
--- a/internal/service/cli.go
+++ b/internal/service/cli.go
@@ -11,6 +11,7 @@ import (
"strings"
"time"
+ "github.com/acepanel/panel/pkg/cert"
"github.com/leonelquinteros/gotext"
"github.com/libtnb/utils/collect"
"github.com/libtnb/utils/hash"
@@ -23,7 +24,6 @@ import (
"github.com/acepanel/panel/internal/biz"
"github.com/acepanel/panel/internal/http/request"
"github.com/acepanel/panel/pkg/api"
- "github.com/acepanel/panel/pkg/cert"
"github.com/acepanel/panel/pkg/config"
"github.com/acepanel/panel/pkg/firewall"
"github.com/acepanel/panel/pkg/io"
@@ -46,10 +46,12 @@ type CliService struct {
backupRepo biz.BackupRepo
websiteRepo biz.WebsiteRepo
databaseServerRepo biz.DatabaseServerRepo
+ certRepo biz.CertRepo
+ certAccountRepo biz.CertAccountRepo
hash hash.Hasher
}
-func NewCliService(t *gotext.Locale, conf *config.Config, db *gorm.DB, appRepo biz.AppRepo, cache biz.CacheRepo, user biz.UserRepo, setting biz.SettingRepo, backup biz.BackupRepo, website biz.WebsiteRepo, databaseServer biz.DatabaseServerRepo) *CliService {
+func NewCliService(t *gotext.Locale, conf *config.Config, db *gorm.DB, appRepo biz.AppRepo, cache biz.CacheRepo, user biz.UserRepo, setting biz.SettingRepo, backup biz.BackupRepo, website biz.WebsiteRepo, databaseServer biz.DatabaseServerRepo, cert biz.CertRepo, certAccount biz.CertAccountRepo) *CliService {
return &CliService{
hr: `+----------------------------------------------------`,
api: api.NewAPI(app.Version, app.Locale),
@@ -63,6 +65,8 @@ func NewCliService(t *gotext.Locale, conf *config.Config, db *gorm.DB, appRepo b
backupRepo: backup,
websiteRepo: website,
databaseServerRepo: databaseServer,
+ certRepo: cert,
+ certAccountRepo: certAccount,
hash: hash.NewArgon2id(),
}
}
@@ -218,9 +222,8 @@ func (s *CliService) UserName(ctx context.Context, cmd *cli.Command) error {
if err := s.db.Where("username", oldUsername).First(user).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return errors.New(s.t.Get("User not exists"))
- } else {
- return errors.New(s.t.Get("Failed to get user: %v", err))
}
+ return errors.New(s.t.Get("Failed to get user: %v", err))
}
user.Username = newUsername
@@ -246,9 +249,8 @@ func (s *CliService) UserPassword(ctx context.Context, cmd *cli.Command) error {
if err := s.db.Where("username", username).First(user).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return errors.New(s.t.Get("User not exists"))
- } else {
- return errors.New(s.t.Get("Failed to get user: %v", err))
}
+ return errors.New(s.t.Get("Failed to get user: %v", err))
}
hashed, err := s.hash.Make(password)
@@ -274,9 +276,8 @@ func (s *CliService) UserTwoFA(ctx context.Context, cmd *cli.Command) error {
if err := s.db.Where("username", username).First(user).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return errors.New(s.t.Get("User not exists"))
- } else {
- return errors.New(s.t.Get("Failed to get user: %v", err))
}
+ return errors.New(s.t.Get("Failed to get user: %v", err))
}
// 已开启,关闭2FA
@@ -359,6 +360,26 @@ func (s *CliService) HTTPSGenerate(ctx context.Context, cmd *cli.Command) error
return err
}
+ if s.conf.HTTP.ACME {
+ ip, err := s.settingRepo.Get(biz.SettingKeyIP)
+ if err != nil || ip == "" {
+ return errors.New(s.t.Get("Please set the panel IP in settings first for ACME certificate generation: %v", err))
+ }
+
+ var user biz.User
+ if err := s.db.First(&user).Error; err != nil {
+ return errors.New(s.t.Get("Failed to get a panel user: %v", err))
+ }
+ account, err := s.certAccountRepo.GetDefault(user.ID)
+ if err != nil {
+ return errors.New(s.t.Get("Failed to get ACME account: %v", err))
+ }
+ crt, key, err = s.certRepo.ObtainPanel(account, names)
+ if err != nil {
+ return errors.New(s.t.Get("Failed to obtain ACME certificate: %v", err))
+ }
+ }
+
if err = io.Write(filepath.Join(app.Root, "panel/storage/cert.pem"), string(crt), 0644); err != nil {
return err
}
@@ -558,7 +579,7 @@ func (s *CliService) DatabaseAddServer(ctx context.Context, cmd *cli.Command) er
Type: cmd.String("type"),
Name: cmd.String("name"),
Host: cmd.String("host"),
- Port: uint(cmd.Uint("port")),
+ Port: cmd.Uint("port"),
Username: cmd.String("username"),
Password: cmd.String("password"),
Remark: cmd.String("remark"),
@@ -646,7 +667,7 @@ func (s *CliService) BackupClear(ctx context.Context, cmd *cli.Command) error {
fmt.Println(s.t.Get("|-Cleaning type: %s", cmd.String("type")))
fmt.Println(s.t.Get("|-Cleaning target: %s", cmd.String("file")))
fmt.Println(s.t.Get("|-Keep count: %d", cmd.Int("save")))
- if err = s.backupRepo.ClearExpired(path, cmd.String("file"), int(cmd.Int("save"))); err != nil {
+ if err = s.backupRepo.ClearExpired(path, cmd.String("file"), cmd.Int("save")); err != nil {
return errors.New(s.t.Get("Cleaning failed: %v", err))
}
fmt.Println(s.hr)
@@ -694,7 +715,7 @@ func (s *CliService) CutoffClear(ctx context.Context, cmd *cli.Command) error {
fmt.Println(s.t.Get("|-Cleaning type: %s", cmd.String("type")))
fmt.Println(s.t.Get("|-Cleaning target: %s", cmd.String("file")))
fmt.Println(s.t.Get("|-Keep count: %d", cmd.Int("save")))
- if err := s.backupRepo.ClearExpired(path, cmd.String("file"), int(cmd.Int("save"))); err != nil {
+ if err := s.backupRepo.ClearExpired(path, cmd.String("file"), cmd.Int("save")); err != nil {
return err
}
fmt.Println(s.hr)
@@ -868,19 +889,33 @@ func (s *CliService) Init(ctx context.Context, cmd *cli.Command) error {
return errors.New(s.t.Get("Already initialized"))
}
+ ip := ""
+ acme := false
+ rv6, err := tools.GetPublicIPv6()
+ if err == nil {
+ ip = rv6
+ acme = true
+ }
+ rv4, err := tools.GetPublicIPv4()
+ if err == nil {
+ ip = rv4
+ acme = true
+ }
+
settings := []biz.Setting{
+ {Key: biz.SettingKeyIP, Value: ip},
{Key: biz.SettingKeyName, Value: "AcePanel"},
{Key: biz.SettingKeyChannel, Value: "stable"},
{Key: biz.SettingKeyVersion, Value: app.Version},
{Key: biz.SettingKeyMonitor, Value: "true"},
{Key: biz.SettingKeyMonitorDays, Value: "30"},
{Key: biz.SettingKeyBackupPath, Value: filepath.Join(app.Root, "backup")},
- {Key: biz.SettingKeyWebsitePath, Value: filepath.Join(app.Root, "wwwroot")},
+ {Key: biz.SettingKeyWebsitePath, Value: filepath.Join(app.Root, "sites")},
{Key: biz.SettingKeyOfflineMode, Value: "false"},
{Key: biz.SettingKeyAutoUpdate, Value: "true"},
{Key: biz.SettingHiddenMenu, Value: "[]"},
}
- if err := s.db.Create(&settings).Error; err != nil {
+ if err = s.db.Create(&settings).Error; err != nil {
return errors.New(s.t.Get("Initialization failed: %v", err))
}
@@ -894,10 +929,6 @@ func (s *CliService) Init(ctx context.Context, cmd *cli.Command) error {
return errors.New(s.t.Get("Initialization failed: %v", err))
}
- if err = s.HTTPSGenerate(ctx, cmd); err != nil {
- return errors.New(s.t.Get("Initialization failed: %v", err))
- }
-
conf, err := config.Load()
if err != nil {
return err
@@ -907,6 +938,7 @@ func (s *CliService) Init(ctx context.Context, cmd *cli.Command) error {
conf.App.APIEndpoint = "api.acepanel.net"
conf.App.DownloadEndpoint = "dl.acepanel.net"
conf.HTTP.Entrance = "/" + str.Random(6)
+ conf.HTTP.ACME = acme
// 随机默认端口
checkPort:
@@ -930,5 +962,11 @@ checkPort:
return err
}
+ s.conf = conf // 更新配置,否则后续签发证书不会使用ACME
+
+ if err = s.HTTPSGenerate(ctx, cmd); err != nil {
+ return errors.New(s.t.Get("Initialization failed: %v", err))
+ }
+
return nil
}
diff --git a/pkg/acme/client.go b/pkg/acme/client.go
index 7ad07836..8211f8f3 100644
--- a/pkg/acme/client.go
+++ b/pkg/acme/client.go
@@ -52,7 +52,6 @@ func (c *Client) UseManualDns(check ...bool) {
// UseHTTP 使用 HTTP 验证
// conf nginx 配置文件路径
-// path 验证文件存放路径
func (c *Client) UseHTTP(conf string) {
c.zClient.ChallengeSolvers = map[string]acmez.Solver{
acme.ChallengeTypeHTTP01: httpSolver{
@@ -61,6 +60,18 @@ func (c *Client) UseHTTP(conf string) {
}
}
+// UsePanel 使用面板 HTTP 验证
+// ip 外网访问 IP 地址
+// conf nginx 配置文件路径
+func (c *Client) UsePanel(ip []string, conf string) {
+ c.zClient.ChallengeSolvers = map[string]acmez.Solver{
+ acme.ChallengeTypeHTTP01: &panelSolver{
+ ip: ip,
+ conf: conf,
+ },
+ }
+}
+
// ObtainCertificate 签发 SSL 证书
func (c *Client) ObtainCertificate(ctx context.Context, domains []string, keyType KeyType) (Certificate, error) {
certPrivateKey, err := generatePrivateKey(keyType)
diff --git a/pkg/acme/solvers.go b/pkg/acme/solvers.go
index c5a956e9..87c79013 100644
--- a/pkg/acme/solvers.go
+++ b/pkg/acme/solvers.go
@@ -2,7 +2,9 @@ package acme
import (
"context"
+ "errors"
"fmt"
+ "net/http"
"os"
"strings"
"time"
@@ -20,10 +22,106 @@ import (
"github.com/mholt/acmez/v3/acme"
"golang.org/x/net/publicsuffix"
+ pkgos "github.com/acepanel/panel/pkg/os"
"github.com/acepanel/panel/pkg/shell"
"github.com/acepanel/panel/pkg/systemctl"
)
+type panelSolver struct {
+ ip []string
+ conf string
+ server *http.Server
+}
+
+func (s *panelSolver) Present(_ context.Context, challenge acme.Challenge) error {
+ // 如果 80 端口没有被占用,则直接起一个内置的 HTTP 服务器验证
+ if !pkgos.TCPPortInUse(80) {
+ return s.presentPanel(challenge)
+ }
+
+ conf := fmt.Sprintf(`server {
+ listen 80;
+ server_name %s;
+ location = %s {
+ default_type text/plain;
+ return 200 %q;
+ }
+}
+`, s.ip, challenge.HTTP01ResourcePath(), challenge.KeyAuthorization)
+
+ f, err := os.OpenFile(s.conf, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
+ if err != nil {
+ return fmt.Errorf("failed to open nginx config %q: %w", s.conf, err)
+ }
+ defer func(f *os.File) { _ = f.Close() }(f)
+
+ if _, err = f.Write([]byte(conf)); err != nil {
+ return fmt.Errorf("failed to write to nginx config %q: %w", s.conf, err)
+ }
+
+ if err = systemctl.Reload("nginx"); err != nil {
+ _, err = shell.Execf("nginx -t")
+ return fmt.Errorf("failed to reload nginx: %w", err)
+ }
+
+ return nil
+}
+
+func (s *panelSolver) presentPanel(challenge acme.Challenge) error {
+ mux := http.NewServeMux()
+ mux.HandleFunc(challenge.HTTP01ResourcePath(), func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Content-Type", "text/plain")
+ _, _ = w.Write([]byte(challenge.KeyAuthorization))
+ })
+
+ s.server = &http.Server{
+ Addr: ":80",
+ Handler: mux,
+ }
+
+ errChan := make(chan error, 1)
+ go func() {
+ if err := s.server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
+ errChan <- err
+ }
+ close(errChan)
+ }()
+
+ // 等待一小段时间确保服务器启动成功
+ select {
+ case err := <-errChan:
+ return fmt.Errorf("failed to start HTTP server: %w", err)
+ case <-time.After(100 * time.Millisecond):
+ return nil
+ }
+}
+
+// CleanUp cleans up the HTTP server if it is the last one to finish.
+func (s *panelSolver) CleanUp(ctx context.Context, _ acme.Challenge) error {
+ // 如果启动了内置 HTTP 服务器,则关闭它
+ if s.server != nil {
+ shutdownCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
+ defer cancel()
+ if err := s.server.Shutdown(shutdownCtx); err != nil {
+ return fmt.Errorf("failed to shutdown HTTP server: %w", err)
+ }
+ s.server = nil
+ return nil
+ }
+
+ // 否则清理 nginx 配置
+ if err := os.WriteFile(s.conf, []byte(""), 0644); err != nil {
+ return fmt.Errorf("failed to write to nginx config %q: %w", s.conf, err)
+ }
+
+ if err := systemctl.Reload("nginx"); err != nil {
+ _, err = shell.Execf("nginx -t")
+ return fmt.Errorf("failed to reload nginx: %w", err)
+ }
+
+ return nil
+}
+
type httpSolver struct {
conf string
}
diff --git a/pkg/config/config.go b/pkg/config/config.go
index 8f325259..1eb259ad 100644
--- a/pkg/config/config.go
+++ b/pkg/config/config.go
@@ -34,6 +34,7 @@ type HTTPConfig struct {
Entrance string `yaml:"entrance"`
EntranceError string `yaml:"entrance_error"`
TLS bool `yaml:"tls"`
+ ACME bool `yaml:"acme"`
LoginCaptcha bool `yaml:"login_captcha"`
IPHeader string `yaml:"ip_header"`
BindDomain []string `yaml:"bind_domain"`
diff --git a/pkg/webserver/nginx/vhost.go b/pkg/webserver/nginx/vhost.go
index 61190f57..1243ddcb 100644
--- a/pkg/webserver/nginx/vhost.go
+++ b/pkg/webserver/nginx/vhost.go
@@ -496,8 +496,6 @@ func (v *baseVhost) SetSSLConfig(cfg *types.SSLConfig) error {
}
// 设置 OCSP
- _ = v.parser.Clear("server.ssl_stapling")
- _ = v.parser.Clear("server.ssl_stapling_verify")
if cfg.OCSP {
if err = v.parser.Set("server", []*config.Directive{
{
@@ -535,6 +533,11 @@ func (v *baseVhost) ClearSSL() error {
_ = v.parser.Clear("server.ssl_ciphers")
_ = v.parser.Clear("server.ssl_prefer_server_ciphers")
_ = v.parser.Clear("server.ssl_early_data")
+ _ = v.parser.Clear("server.ssl_stapling")
+ _ = v.parser.Clear("server.ssl_stapling_verify")
+ _ = v.setHSTS(false)
+ _ = v.setHTTPSRedirect(false)
+ _ = v.setAltSvc("")
return nil
}
diff --git a/web/src/api/apps/openresty/index.ts b/web/src/api/apps/openresty/index.ts
new file mode 100644
index 00000000..3a7f09b5
--- /dev/null
+++ b/web/src/api/apps/openresty/index.ts
@@ -0,0 +1,14 @@
+import { http } from '@/utils'
+
+export default {
+ // 负载状态
+ load: (): any => http.Get('/apps/openresty/load'),
+ // 获取配置
+ config: (): any => http.Get('/apps/openresty/config'),
+ // 保存配置
+ saveConfig: (config: string): any => http.Post('/apps/openresty/config', { config }),
+ // 获取错误日志
+ errorLog: (): any => http.Get('/apps/openresty/error_log'),
+ // 清空错误日志
+ clearErrorLog: (): any => http.Post('/apps/openresty/clear_error_log')
+}
diff --git a/web/src/views/apps/nginx/types.ts b/web/src/views/apps/nginx/types.ts
deleted file mode 100644
index f555524d..00000000
--- a/web/src/views/apps/nginx/types.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-export interface Task {
- id: number
- name: string
- status: string
- shell: string
- log: string
- created_at: string
- updated_at: string
-}
diff --git a/web/src/views/apps/openresty/IndexView.vue b/web/src/views/apps/openresty/IndexView.vue
new file mode 100644
index 00000000..3e1251e6
--- /dev/null
+++ b/web/src/views/apps/openresty/IndexView.vue
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{
+ $gettext(
+ 'This modifies the OpenResty main configuration file. If you do not understand the meaning of each parameter, please do not modify it randomly!'
+ )
+ }}
+
+
+
+
+ {{ $gettext('Save') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ $gettext('Clear Log') }}
+
+
+
+
+
+
+
+
diff --git a/web/src/views/apps/openresty/route.ts b/web/src/views/apps/openresty/route.ts
index c531d659..dd4a2213 100644
--- a/web/src/views/apps/openresty/route.ts
+++ b/web/src/views/apps/openresty/route.ts
@@ -11,7 +11,7 @@ export default {
{
name: 'apps-openresty-index',
path: '',
- component: () => import('../nginx/IndexView.vue'),
+ component: () => import('./IndexView.vue'),
meta: {
title: 'OpenResty',
role: ['admin'],
diff --git a/web/src/views/setting/SettingBase.vue b/web/src/views/setting/SettingBase.vue
index 23157d9d..a4ed57ce 100644
--- a/web/src/views/setting/SettingBase.vue
+++ b/web/src/views/setting/SettingBase.vue
@@ -50,10 +50,10 @@ const channels = [
-
+
-
+