main.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. package main
  2. import (
  3. "auto-ssl/config"
  4. "auto-ssl/handlers"
  5. "auto-ssl/services"
  6. "log"
  7. "os"
  8. "time"
  9. "github.com/gin-contrib/cors"
  10. "github.com/gin-gonic/gin"
  11. "github.com/robfig/cron/v3"
  12. )
  13. func main() {
  14. cfg := config.Load()
  15. // Initialize database
  16. config.InitDB(cfg)
  17. // Setup Gin
  18. gin.SetMode(gin.ReleaseMode)
  19. r := gin.Default()
  20. // CORS for Vue frontend
  21. r.Use(cors.New(cors.Config{
  22. AllowOrigins: []string{"*"},
  23. AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
  24. AllowHeaders: []string{"Origin", "Content-Type", "Accept", "Authorization"},
  25. AllowCredentials: true,
  26. }))
  27. // Serve static files for frontend
  28. r.Static("/assets", "./dist/assets")
  29. r.StaticFile("/favicon.ico", "./dist/favicon.ico")
  30. r.StaticFile("/", "./dist/index.html")
  31. r.NoRoute(func(c *gin.Context) {
  32. c.File("./dist/index.html")
  33. })
  34. // API routes
  35. api := r.Group("/api")
  36. {
  37. certHandler := handlers.NewCertHandler(cfg)
  38. // Certificate management
  39. api.GET("/certificates", certHandler.ListCertificates)
  40. api.GET("/certificates/:id", certHandler.GetCertificate)
  41. api.POST("/certificates", certHandler.CreateCertificate)
  42. api.PUT("/certificates/:id", certHandler.UpdateCertificate)
  43. api.DELETE("/certificates/:id", certHandler.DeleteCertificate)
  44. api.POST("/certificates/:id/renew", certHandler.RenewCertificate)
  45. api.GET("/certificates/:id/files", certHandler.GetCertFiles)
  46. // Utility
  47. api.GET("/renewals/check", certHandler.CheckRenewals)
  48. api.GET("/stats", certHandler.Stats)
  49. }
  50. // Setup cron for auto-renewal (runs daily at 3:00 AM)
  51. c := cron.New()
  52. c.AddFunc("0 3 * * *", func() {
  53. log.Println("Running scheduled certificate renewal check...")
  54. var certs []config.Certificate
  55. config.DB.Where("auto_renew = ? AND status = ?", true, "active").Find(&certs)
  56. for _, cert := range certs {
  57. if cert.ExpiresAt != nil && time.Until(*cert.ExpiresAt).Hours() < float64(cert.RenewDays*24) {
  58. log.Printf("Auto-renewing certificate for %s (expires %s)", cert.Domain, cert.ExpiresAt.Format(time.RFC3339))
  59. if err := services.RenewCertificate(&cert, cfg); err != nil {
  60. cert.Status = "error"
  61. cert.ErrorMessage = "auto renew: " + err.Error()
  62. log.Printf("Auto-renew failed for %s: %v", cert.Domain, err)
  63. } else {
  64. log.Printf("Auto-renew succeeded for %s", cert.Domain)
  65. }
  66. config.DB.Save(&cert)
  67. }
  68. }
  69. })
  70. c.Start()
  71. // Setup HTTP server for ACME HTTP-01 challenges (port 80)
  72. httpPort := os.Getenv("HTTP_PORT")
  73. if httpPort == "" {
  74. httpPort = "80"
  75. }
  76. go func() {
  77. acme := gin.New()
  78. acme.Use(gin.Recovery())
  79. // HTTP-01 challenge handler from lego
  80. log.Printf("ACME HTTP challenge server listening on :%s", httpPort)
  81. if err := acme.Run(":" + httpPort); err != nil {
  82. log.Printf("ACME HTTP server (port %s) exited: %v", httpPort, err)
  83. }
  84. }()
  85. log.Printf("AutoSSL server starting on :%s", cfg.Port)
  86. if err := r.Run(":" + cfg.Port); err != nil {
  87. log.Fatalf("Failed to start server: %v", err)
  88. }
  89. }