config.go raw
1 package main
2
3 import (
4 "os"
5 "time"
6
7 "go-simpler.org/env"
8 "next.orly.dev/pkg/lol/chk"
9 "next.orly.dev/pkg/lol/log"
10 )
11
12 // Config holds the configuration for the certificate manager.
13 type Config struct {
14 // Domain is the wildcard domain to obtain a certificate for (e.g., "*.myapp.com")
15 Domain string `env:"ORLY_CERTS_DOMAIN" required:"true" usage:"wildcard domain (e.g., *.myapp.com)"`
16
17 // Email is the email address for the Let's Encrypt account
18 Email string `env:"ORLY_CERTS_EMAIL" required:"true" usage:"email for Let's Encrypt account"`
19
20 // DNSProvider is the name of the DNS provider (cloudflare, route53, hetzner, etc.)
21 DNSProvider string `env:"ORLY_CERTS_DNS_PROVIDER" required:"true" usage:"DNS provider name (cloudflare, route53, hetzner, etc.)"`
22
23 // OutputDir is the directory where certificates will be stored
24 OutputDir string `env:"ORLY_CERTS_OUTPUT_DIR" default:"/var/cache/orly-certs" usage:"certificate output directory"`
25
26 // RenewDays is the number of days before expiry to trigger renewal
27 RenewDays int `env:"ORLY_CERTS_RENEW_DAYS" default:"30" usage:"renew certificate when expiring within N days"`
28
29 // CheckInterval is how often to check for renewal
30 CheckInterval time.Duration `env:"ORLY_CERTS_CHECK_INTERVAL" default:"12h" usage:"how often to check for renewal"`
31
32 // ACMEServer is the ACME server URL (empty for production Let's Encrypt)
33 ACMEServer string `env:"ORLY_CERTS_ACME_SERVER" default:"" usage:"ACME server URL (empty for production)"`
34
35 // LogLevel is the log level
36 LogLevel string `env:"ORLY_CERTS_LOG_LEVEL" default:"info" usage:"log level (trace, debug, info, warn, error)"`
37
38 // AccountKeyPath is the path to store the ACME account private key
39 AccountKeyPath string `env:"ORLY_CERTS_ACCOUNT_KEY" default:"" usage:"path to ACME account key (auto-generated if empty)"`
40 }
41
42 // ProductionACMEServer is the Let's Encrypt production ACME server
43 const ProductionACMEServer = "https://acme-v02.api.letsencrypt.org/directory"
44
45 // StagingACMEServer is the Let's Encrypt staging ACME server (for testing)
46 const StagingACMEServer = "https://acme-staging-v02.api.letsencrypt.org/directory"
47
48 // loadConfig loads configuration from environment variables.
49 func loadConfig() *Config {
50 cfg := &Config{}
51 if err := env.Load(cfg, nil); chk.E(err) {
52 log.E.F("failed to load config: %v", err)
53 os.Exit(1)
54 }
55 return cfg
56 }
57
58 // ACMEServerURL returns the ACME server URL to use.
59 func (c *Config) ACMEServerURL() string {
60 if c.ACMEServer != "" {
61 return c.ACMEServer
62 }
63 return ProductionACMEServer
64 }
65
66 // BaseDomain extracts the base domain from the wildcard domain.
67 // e.g., "*.myapp.com" -> "myapp.com"
68 func (c *Config) BaseDomain() string {
69 domain := c.Domain
70 if len(domain) > 2 && domain[:2] == "*." {
71 return domain[2:]
72 }
73 return domain
74 }
75