feat: AutoSSL certificate management tool with Web UI
This commit is contained in:
+103
@@ -0,0 +1,103 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"auto-ssl/config"
|
||||
"auto-ssl/handlers"
|
||||
"auto-ssl/services"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/gin-contrib/cors"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/robfig/cron/v3"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cfg := config.Load()
|
||||
|
||||
// Initialize database
|
||||
config.InitDB(cfg)
|
||||
|
||||
// Setup Gin
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
r := gin.Default()
|
||||
|
||||
// CORS for Vue frontend
|
||||
r.Use(cors.New(cors.Config{
|
||||
AllowOrigins: []string{"*"},
|
||||
AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
|
||||
AllowHeaders: []string{"Origin", "Content-Type", "Accept", "Authorization"},
|
||||
AllowCredentials: true,
|
||||
}))
|
||||
|
||||
// Serve static files for frontend
|
||||
r.Static("/assets", "./dist/assets")
|
||||
r.StaticFile("/favicon.ico", "./dist/favicon.ico")
|
||||
r.StaticFile("/", "./dist/index.html")
|
||||
r.NoRoute(func(c *gin.Context) {
|
||||
c.File("./dist/index.html")
|
||||
})
|
||||
|
||||
// API routes
|
||||
api := r.Group("/api")
|
||||
{
|
||||
certHandler := handlers.NewCertHandler(cfg)
|
||||
|
||||
// Certificate management
|
||||
api.GET("/certificates", certHandler.ListCertificates)
|
||||
api.GET("/certificates/:id", certHandler.GetCertificate)
|
||||
api.POST("/certificates", certHandler.CreateCertificate)
|
||||
api.PUT("/certificates/:id", certHandler.UpdateCertificate)
|
||||
api.DELETE("/certificates/:id", certHandler.DeleteCertificate)
|
||||
api.POST("/certificates/:id/renew", certHandler.RenewCertificate)
|
||||
api.GET("/certificates/:id/files", certHandler.GetCertFiles)
|
||||
|
||||
// Utility
|
||||
api.GET("/renewals/check", certHandler.CheckRenewals)
|
||||
api.GET("/stats", certHandler.Stats)
|
||||
}
|
||||
|
||||
// Setup cron for auto-renewal (runs daily at 3:00 AM)
|
||||
c := cron.New()
|
||||
c.AddFunc("0 3 * * *", func() {
|
||||
log.Println("Running scheduled certificate renewal check...")
|
||||
var certs []config.Certificate
|
||||
config.DB.Where("auto_renew = ? AND status = ?", true, "active").Find(&certs)
|
||||
|
||||
for _, cert := range certs {
|
||||
if cert.ExpiresAt != nil && time.Until(*cert.ExpiresAt).Hours() < float64(cert.RenewDays*24) {
|
||||
log.Printf("Auto-renewing certificate for %s (expires %s)", cert.Domain, cert.ExpiresAt.Format(time.RFC3339))
|
||||
if err := services.RenewCertificate(&cert, cfg); err != nil {
|
||||
cert.Status = "error"
|
||||
cert.ErrorMessage = "auto renew: " + err.Error()
|
||||
log.Printf("Auto-renew failed for %s: %v", cert.Domain, err)
|
||||
} else {
|
||||
log.Printf("Auto-renew succeeded for %s", cert.Domain)
|
||||
}
|
||||
config.DB.Save(&cert)
|
||||
}
|
||||
}
|
||||
})
|
||||
c.Start()
|
||||
|
||||
// Setup HTTP server for ACME HTTP-01 challenges (port 80)
|
||||
httpPort := os.Getenv("HTTP_PORT")
|
||||
if httpPort == "" {
|
||||
httpPort = "80"
|
||||
}
|
||||
go func() {
|
||||
acme := gin.New()
|
||||
acme.Use(gin.Recovery())
|
||||
// HTTP-01 challenge handler from lego
|
||||
log.Printf("ACME HTTP challenge server listening on :%s", httpPort)
|
||||
if err := acme.Run(":" + httpPort); err != nil {
|
||||
log.Printf("ACME HTTP server (port %s) exited: %v", httpPort, err)
|
||||
}
|
||||
}()
|
||||
|
||||
log.Printf("AutoSSL server starting on :%s", cfg.Port)
|
||||
if err := r.Run(":" + cfg.Port); err != nil {
|
||||
log.Fatalf("Failed to start server: %v", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user