mirror of
https://github.com/joohoi/acme-dns.git
synced 2025-03-10 12:50:17 +07:00

No separate certmagic cache needed. Default config and cache are sufficient to handle the certificates for the HTTP API. Updated to certmagic v0.20.
204 lines
5.7 KiB
Go
204 lines
5.7 KiB
Go
//go:build !test
|
|
// +build !test
|
|
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"flag"
|
|
stdlog "log"
|
|
"net/http"
|
|
"os"
|
|
"strings"
|
|
"syscall"
|
|
|
|
"github.com/caddyserver/certmagic"
|
|
legolog "github.com/go-acme/lego/v3/log"
|
|
"github.com/julienschmidt/httprouter"
|
|
"github.com/rs/cors"
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
func main() {
|
|
// Created files are not world writable
|
|
syscall.Umask(0077)
|
|
configPtr := flag.String("c", "/etc/acme-dns/config.cfg", "config file location")
|
|
flag.Parse()
|
|
// Read global config
|
|
var err error
|
|
if fileIsAccessible(*configPtr) {
|
|
log.WithFields(log.Fields{"file": *configPtr}).Info("Using config file")
|
|
Config, err = readConfig(*configPtr)
|
|
} else if fileIsAccessible("./config.cfg") {
|
|
log.WithFields(log.Fields{"file": "./config.cfg"}).Info("Using config file")
|
|
Config, err = readConfig("./config.cfg")
|
|
} else {
|
|
log.Errorf("Configuration file not found.")
|
|
os.Exit(1)
|
|
}
|
|
if err != nil {
|
|
log.Errorf("Encountered an error while trying to read configuration file: %s", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
setupLogging(Config.Logconfig.Format, Config.Logconfig.Level)
|
|
|
|
// Open database
|
|
newDB := new(acmedb)
|
|
err = newDB.Init(Config.Database.Engine, Config.Database.Connection)
|
|
if err != nil {
|
|
log.Errorf("Could not open database [%v]", err)
|
|
os.Exit(1)
|
|
} else {
|
|
log.Info("Connected to database")
|
|
}
|
|
DB = newDB
|
|
defer DB.Close()
|
|
|
|
// Error channel for servers
|
|
errChan := make(chan error, 1)
|
|
|
|
// DNS server
|
|
dnsservers := make([]*DNSServer, 0)
|
|
if strings.HasPrefix(Config.General.Proto, "both") {
|
|
// Handle the case where DNS server should be started for both udp and tcp
|
|
udpProto := "udp"
|
|
tcpProto := "tcp"
|
|
if strings.HasSuffix(Config.General.Proto, "4") {
|
|
udpProto += "4"
|
|
tcpProto += "4"
|
|
} else if strings.HasSuffix(Config.General.Proto, "6") {
|
|
udpProto += "6"
|
|
tcpProto += "6"
|
|
}
|
|
dnsServerUDP := NewDNSServer(DB, Config.General.Listen, udpProto, Config.General.Domain)
|
|
dnsservers = append(dnsservers, dnsServerUDP)
|
|
dnsServerUDP.ParseRecords(Config)
|
|
dnsServerTCP := NewDNSServer(DB, Config.General.Listen, tcpProto, Config.General.Domain)
|
|
dnsservers = append(dnsservers, dnsServerTCP)
|
|
// No need to parse records from config again
|
|
dnsServerTCP.Domains = dnsServerUDP.Domains
|
|
dnsServerTCP.SOA = dnsServerUDP.SOA
|
|
go dnsServerUDP.Start(errChan)
|
|
go dnsServerTCP.Start(errChan)
|
|
} else {
|
|
dnsServer := NewDNSServer(DB, Config.General.Listen, Config.General.Proto, Config.General.Domain)
|
|
dnsservers = append(dnsservers, dnsServer)
|
|
dnsServer.ParseRecords(Config)
|
|
go dnsServer.Start(errChan)
|
|
}
|
|
|
|
// HTTP API
|
|
go startHTTPAPI(errChan, Config, dnsservers)
|
|
|
|
// block waiting for error
|
|
for {
|
|
err = <-errChan
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func startHTTPAPI(errChan chan error, config DNSConfig, dnsservers []*DNSServer) {
|
|
// Setup http logger
|
|
logger := log.New()
|
|
logwriter := logger.Writer()
|
|
defer logwriter.Close()
|
|
// Setup logging for different dependencies to log with logrus
|
|
// Certmagic
|
|
stdlog.SetOutput(logwriter)
|
|
// Lego
|
|
legolog.Logger = logger
|
|
|
|
api := httprouter.New()
|
|
c := cors.New(cors.Options{
|
|
AllowedOrigins: Config.API.CorsOrigins,
|
|
AllowedMethods: []string{"GET", "POST"},
|
|
OptionsPassthrough: false,
|
|
Debug: Config.General.Debug,
|
|
})
|
|
if Config.General.Debug {
|
|
// Logwriter for saner log output
|
|
c.Log = stdlog.New(logwriter, "", 0)
|
|
}
|
|
if !Config.API.DisableRegistration {
|
|
api.POST("/register", webRegisterPost)
|
|
}
|
|
api.POST("/update", Auth(webUpdatePost))
|
|
api.GET("/health", healthCheck)
|
|
|
|
host := Config.API.IP + ":" + Config.API.Port
|
|
|
|
// TLS specific general settings
|
|
cfg := &tls.Config{
|
|
MinVersion: tls.VersionTLS12,
|
|
}
|
|
provider := NewChallengeProvider(dnsservers)
|
|
storage := certmagic.FileStorage{Path: Config.API.ACMECacheDir}
|
|
|
|
// Set up certmagic for getting certificate for acme-dns api
|
|
certmagic.DefaultACME.DNS01Solver = &provider
|
|
certmagic.DefaultACME.Agreed = true
|
|
if Config.API.TLS == "letsencrypt" {
|
|
certmagic.DefaultACME.CA = certmagic.LetsEncryptProductionCA
|
|
} else {
|
|
certmagic.DefaultACME.CA = certmagic.LetsEncryptStagingCA
|
|
}
|
|
certmagic.DefaultACME.Email = Config.API.NotificationEmail
|
|
certmagic.Default.Storage = &storage
|
|
certmagic.Default.DefaultServerName = Config.General.Domain
|
|
|
|
magic := certmagic.NewDefault()
|
|
var err error
|
|
switch Config.API.TLS {
|
|
case "letsencryptstaging":
|
|
err = magic.ManageAsync(context.Background(), []string{Config.General.Domain})
|
|
if err != nil {
|
|
errChan <- err
|
|
return
|
|
}
|
|
cfg.GetCertificate = magic.GetCertificate
|
|
|
|
srv := &http.Server{
|
|
Addr: host,
|
|
Handler: c.Handler(api),
|
|
TLSConfig: cfg,
|
|
ErrorLog: stdlog.New(logwriter, "", 0),
|
|
}
|
|
log.WithFields(log.Fields{"host": host, "domain": Config.General.Domain}).Info("Listening HTTPS")
|
|
err = srv.ListenAndServeTLS("", "")
|
|
case "letsencrypt":
|
|
err = magic.ManageAsync(context.Background(), []string{Config.General.Domain})
|
|
if err != nil {
|
|
errChan <- err
|
|
return
|
|
}
|
|
cfg.GetCertificate = magic.GetCertificate
|
|
srv := &http.Server{
|
|
Addr: host,
|
|
Handler: c.Handler(api),
|
|
TLSConfig: cfg,
|
|
ErrorLog: stdlog.New(logwriter, "", 0),
|
|
}
|
|
log.WithFields(log.Fields{"host": host, "domain": Config.General.Domain}).Info("Listening HTTPS")
|
|
err = srv.ListenAndServeTLS("", "")
|
|
case "cert":
|
|
srv := &http.Server{
|
|
Addr: host,
|
|
Handler: c.Handler(api),
|
|
TLSConfig: cfg,
|
|
ErrorLog: stdlog.New(logwriter, "", 0),
|
|
}
|
|
log.WithFields(log.Fields{"host": host}).Info("Listening HTTPS")
|
|
err = srv.ListenAndServeTLS(Config.API.TLSCertFullchain, Config.API.TLSCertPrivkey)
|
|
default:
|
|
log.WithFields(log.Fields{"host": host}).Info("Listening HTTP")
|
|
err = http.ListenAndServe(host, c.Handler(api))
|
|
}
|
|
if err != nil {
|
|
errChan <- err
|
|
}
|
|
}
|