diff --git a/cmd/main.go b/cmd/main.go
index ceec3d5..222c295 100644
--- a/cmd/main.go
+++ b/cmd/main.go
@@ -102,7 +102,12 @@ func Serve(ctx *cli.Context) error {
 		keyCache, challengeCache, dnsLookupCache, canonicalDomainCache,
 		keyDatabase))
 
-	certificates.SetupCertificates(mainDomainSuffix, acmeAPI, acmeMail, acmeEabHmac, acmeEabKID, dnsProvider, acmeUseRateLimits, acmeAcceptTerms, enableHTTPServer, challengeCache, keyDatabase)
+	acmeConfig, err := certificates.SetupAcmeConfig(acmeAPI, acmeMail, acmeEabHmac, acmeEabKID, acmeAcceptTerms)
+	if err != nil {
+		return err
+	}
+
+	certificates.SetupCertificates(mainDomainSuffix, dnsProvider, acmeConfig, acmeUseRateLimits, enableHTTPServer, challengeCache, keyDatabase)
 
 	if enableHTTPServer {
 		go func() {
diff --git a/server/certificates/acme_account.go b/server/certificates/acme_account.go
new file mode 100644
index 0000000..2ee2e80
--- /dev/null
+++ b/server/certificates/acme_account.go
@@ -0,0 +1,27 @@
+package certificates
+
+import (
+	"crypto"
+
+	"github.com/go-acme/lego/v4/registration"
+)
+
+type AcmeAccount struct {
+	Email        string
+	Registration *registration.Resource
+	Key          crypto.PrivateKey `json:"-"`
+	KeyPEM       string            `json:"Key"`
+}
+
+// make sure AcmeAccount match User interface
+var _ registration.User = &AcmeAccount{}
+
+func (u *AcmeAccount) GetEmail() string {
+	return u.Email
+}
+func (u AcmeAccount) GetRegistration() *registration.Resource {
+	return u.Registration
+}
+func (u *AcmeAccount) GetPrivateKey() crypto.PrivateKey {
+	return u.Key
+}
diff --git a/server/certificates/certificates.go b/server/certificates/certificates.go
index fb61bd8..b20f623 100644
--- a/server/certificates/certificates.go
+++ b/server/certificates/certificates.go
@@ -2,7 +2,6 @@ package certificates
 
 import (
 	"bytes"
-	"crypto"
 	"crypto/ecdsa"
 	"crypto/elliptic"
 	"crypto/rand"
@@ -12,15 +11,12 @@ import (
 	"encoding/json"
 	"errors"
 	"io/ioutil"
-	"log"
 	"os"
 	"strconv"
 	"strings"
 	"sync"
 	"time"
 
-	"github.com/reugn/equalizer"
-
 	"github.com/go-acme/lego/v4/certcrypto"
 	"github.com/go-acme/lego/v4/certificate"
 	"github.com/go-acme/lego/v4/challenge"
@@ -28,6 +24,8 @@ import (
 	"github.com/go-acme/lego/v4/lego"
 	"github.com/go-acme/lego/v4/providers/dns"
 	"github.com/go-acme/lego/v4/registration"
+	"github.com/reugn/equalizer"
+	"github.com/rs/zerolog/log"
 
 	"codeberg.org/codeberg/pages/server/cache"
 	"codeberg.org/codeberg/pages/server/database"
@@ -147,26 +145,6 @@ func checkUserLimit(user string) error {
 	return nil
 }
 
-var myAcmeAccount AcmeAccount
-var myAcmeConfig *lego.Config
-
-type AcmeAccount struct {
-	Email        string
-	Registration *registration.Resource
-	Key          crypto.PrivateKey `json:"-"`
-	KeyPEM       string            `json:"Key"`
-}
-
-func (u *AcmeAccount) GetEmail() string {
-	return u.Email
-}
-func (u AcmeAccount) GetRegistration() *registration.Resource {
-	return u.Registration
-}
-func (u *AcmeAccount) GetPrivateKey() crypto.PrivateKey {
-	return u.Key
-}
-
 var acmeClient, mainDomainAcmeClient *lego.Client
 var acmeClientCertificateLimitPerUser = map[string]*equalizer.TokenBucket{}
 
@@ -331,15 +309,12 @@ func obtainCert(acmeClient *lego.Client, domains []string, renew *certificate.Re
 	return tlsCertificate, nil
 }
 
-func SetupCertificates(mainDomainSuffix []byte, acmeAPI, acmeMail, acmeEabHmac, acmeEabKID, dnsProvider string, acmeUseRateLimits, acmeAcceptTerms, enableHTTPServer bool, challengeCache cache.SetGetKey, keyDatabase database.KeyDB) {
-	// getting main cert before ACME account so that we can panic here on database failure without hitting rate limits
-	mainCertBytes, err := keyDatabase.Get(mainDomainSuffix)
-	if err != nil {
-		// key database is not working
-		panic(err)
-	}
+func SetupAcmeConfig(acmeAPI, acmeMail, acmeEabHmac, acmeEabKID string, acmeAcceptTerms bool) (*lego.Config, error) {
+	const configFile = "acme-account.json"
+	var myAcmeAccount AcmeAccount
+	var myAcmeConfig *lego.Config
 
-	if account, err := ioutil.ReadFile("acme-account.json"); err == nil {
+	if account, err := ioutil.ReadFile(configFile); err == nil {
 		err = json.Unmarshal(account, &myAcmeAccount)
 		if err != nil {
 			panic(err)
@@ -351,66 +326,81 @@ func SetupCertificates(mainDomainSuffix []byte, acmeAPI, acmeMail, acmeEabHmac,
 		myAcmeConfig = lego.NewConfig(&myAcmeAccount)
 		myAcmeConfig.CADirURL = acmeAPI
 		myAcmeConfig.Certificate.KeyType = certcrypto.RSA2048
+
+		// Validate Config
 		_, err := lego.NewClient(myAcmeConfig)
 		if err != nil {
+			// TODO: should we fail hard instead?
 			log.Printf("[ERROR] Can't create ACME client, continuing with mock certs only: %s", err)
 		}
-	} else if os.IsNotExist(err) {
-		privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
-		if err != nil {
-			panic(err)
-		}
-		myAcmeAccount = AcmeAccount{
-			Email:  acmeMail,
-			Key:    privateKey,
-			KeyPEM: string(certcrypto.PEMEncode(privateKey)),
-		}
-		myAcmeConfig = lego.NewConfig(&myAcmeAccount)
-		myAcmeConfig.CADirURL = acmeAPI
-		myAcmeConfig.Certificate.KeyType = certcrypto.RSA2048
-		tempClient, err := lego.NewClient(myAcmeConfig)
-		if err != nil {
-			log.Printf("[ERROR] Can't create ACME client, continuing with mock certs only: %s", err)
-		} else {
-			// accept terms & log in to EAB
-			if acmeEabKID == "" || acmeEabHmac == "" {
-				reg, err := tempClient.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: acmeAcceptTerms})
-				if err != nil {
-					log.Printf("[ERROR] Can't register ACME account, continuing with mock certs only: %s", err)
-				} else {
-					myAcmeAccount.Registration = reg
-				}
-			} else {
-				reg, err := tempClient.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{
-					TermsOfServiceAgreed: acmeAcceptTerms,
-					Kid:                  acmeEabKID,
-					HmacEncoded:          acmeEabHmac,
-				})
-				if err != nil {
-					log.Printf("[ERROR] Can't register ACME account, continuing with mock certs only: %s", err)
-				} else {
-					myAcmeAccount.Registration = reg
-				}
-			}
+		return myAcmeConfig, nil
+	} else if !os.IsNotExist(err) {
+		return nil, err
+	}
 
-			if myAcmeAccount.Registration != nil {
-				acmeAccountJson, err := json.Marshal(myAcmeAccount)
-				if err != nil {
-					log.Printf("[FAIL] Error during json.Marshal(myAcmeAccount), waiting for manual restart to avoid rate limits: %s", err)
-					select {}
-				}
-				err = ioutil.WriteFile("acme-account.json", acmeAccountJson, 0600)
-				if err != nil {
-					log.Printf("[FAIL] Error during ioutil.WriteFile(\"acme-account.json\"), waiting for manual restart to avoid rate limits: %s", err)
-					select {}
-				}
+	privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+	if err != nil {
+		panic(err)
+	}
+	myAcmeAccount = AcmeAccount{
+		Email:  acmeMail,
+		Key:    privateKey,
+		KeyPEM: string(certcrypto.PEMEncode(privateKey)),
+	}
+	myAcmeConfig = lego.NewConfig(&myAcmeAccount)
+	myAcmeConfig.CADirURL = acmeAPI
+	myAcmeConfig.Certificate.KeyType = certcrypto.RSA2048
+	tempClient, err := lego.NewClient(myAcmeConfig)
+	if err != nil {
+		log.Printf("[ERROR] Can't create ACME client, continuing with mock certs only: %s", err)
+	} else {
+		// accept terms & log in to EAB
+		if acmeEabKID == "" || acmeEabHmac == "" {
+			reg, err := tempClient.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: acmeAcceptTerms})
+			if err != nil {
+				log.Printf("[ERROR] Can't register ACME account, continuing with mock certs only: %s", err)
+			} else {
+				myAcmeAccount.Registration = reg
+			}
+		} else {
+			reg, err := tempClient.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{
+				TermsOfServiceAgreed: acmeAcceptTerms,
+				Kid:                  acmeEabKID,
+				HmacEncoded:          acmeEabHmac,
+			})
+			if err != nil {
+				log.Printf("[ERROR] Can't register ACME account, continuing with mock certs only: %s", err)
+			} else {
+				myAcmeAccount.Registration = reg
 			}
 		}
-	} else {
+
+		if myAcmeAccount.Registration != nil {
+			acmeAccountJson, err := json.Marshal(myAcmeAccount)
+			if err != nil {
+				log.Printf("[FAIL] Error during json.Marshal(myAcmeAccount), waiting for manual restart to avoid rate limits: %s", err)
+				select {}
+			}
+			err = ioutil.WriteFile(configFile, acmeAccountJson, 0600)
+			if err != nil {
+				log.Printf("[FAIL] Error during ioutil.WriteFile(\"acme-account.json\"), waiting for manual restart to avoid rate limits: %s", err)
+				select {}
+			}
+		}
+	}
+
+	return myAcmeConfig, nil
+}
+
+func SetupCertificates(mainDomainSuffix []byte, dnsProvider string, acmeConfig *lego.Config, acmeUseRateLimits, enableHTTPServer bool, challengeCache cache.SetGetKey, keyDatabase database.KeyDB) {
+	// getting main cert before ACME account so that we can panic here on database failure without hitting rate limits
+	mainCertBytes, err := keyDatabase.Get(mainDomainSuffix)
+	if err != nil {
+		// key database is not working
 		panic(err)
 	}
 
-	acmeClient, err = lego.NewClient(myAcmeConfig)
+	acmeClient, err = lego.NewClient(acmeConfig)
 	if err != nil {
 		log.Printf("[ERROR] Can't create ACME client, continuing with mock certs only: %s", err)
 	} else {
@@ -426,7 +416,7 @@ func SetupCertificates(mainDomainSuffix []byte, acmeAPI, acmeMail, acmeEabHmac,
 		}
 	}
 
-	mainDomainAcmeClient, err = lego.NewClient(myAcmeConfig)
+	mainDomainAcmeClient, err = lego.NewClient(acmeConfig)
 	if err != nil {
 		log.Printf("[ERROR] Can't create ACME client, continuing with mock certs only: %s", err)
 	} else {