diff --git a/cmd/main.go b/cmd/main.go
index be33940..a7d606d 100644
--- a/cmd/main.go
+++ b/cmd/main.go
@@ -15,6 +15,7 @@ import (
 	"github.com/valyala/fasthttp"
 
 	"codeberg.org/codeberg/pages/server"
+	"codeberg.org/codeberg/pages/server/utils"
 )
 
 // AllowedCorsDomains lists the domains for which Cross-Origin Resource Sharing is allowed.
@@ -91,7 +92,7 @@ func Serve(ctx *cli.Context) error {
 			challengePath := []byte("/.well-known/acme-challenge/")
 			err := fasthttp.ListenAndServe("[::]:80", func(ctx *fasthttp.RequestCtx) {
 				if bytes.HasPrefix(ctx.Path(), challengePath) {
-					challenge, ok := server.ChallengeCache.Get(string(server.TrimHostPort(ctx.Host())) + "/" + string(bytes.TrimPrefix(ctx.Path(), challengePath)))
+					challenge, ok := server.ChallengeCache.Get(string(utils.TrimHostPort(ctx.Host())) + "/" + string(bytes.TrimPrefix(ctx.Path(), challengePath)))
 					if !ok || challenge == nil {
 						ctx.SetStatusCode(http.StatusNotFound)
 						ctx.SetBodyString("no challenge for this token")
diff --git a/server/certificates.go b/server/certificates.go
index 8ac158d..5339375 100644
--- a/server/certificates.go
+++ b/server/certificates.go
@@ -14,12 +14,6 @@ import (
 	"encoding/json"
 	"encoding/pem"
 	"errors"
-	"github.com/OrlovEvgeny/go-mcache"
-	"github.com/akrylysov/pogreb/fs"
-	"github.com/go-acme/lego/v4/certificate"
-	"github.com/go-acme/lego/v4/challenge"
-	"github.com/go-acme/lego/v4/challenge/tlsalpn01"
-	"github.com/go-acme/lego/v4/providers/dns"
 	"io/ioutil"
 	"log"
 	"math/big"
@@ -29,12 +23,20 @@ import (
 	"sync"
 	"time"
 
+	"github.com/OrlovEvgeny/go-mcache"
 	"github.com/akrylysov/pogreb"
+	"github.com/akrylysov/pogreb/fs"
 	"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"
+	"github.com/go-acme/lego/v4/challenge/tlsalpn01"
 	"github.com/go-acme/lego/v4/lego"
+	"github.com/go-acme/lego/v4/providers/dns"
 	"github.com/go-acme/lego/v4/registration"
+
+	"codeberg.org/codeberg/pages/server/database"
 )
 
 // TlsConfig returns the configuration for generating, serving and cleaning up Let's Encrypt certificates.
@@ -212,7 +214,7 @@ func (a AcmeHTTPChallengeProvider) CleanUp(domain, token, _ string) error {
 func retrieveCertFromDB(sni, mainDomainSuffix []byte, dnsProvider string, acmeUseRateLimits bool) (tls.Certificate, bool) {
 	// parse certificate from database
 	res := &certificate.Resource{}
-	if !PogrebGet(KeyDatabase, sni, res) {
+	if !database.PogrebGet(KeyDatabase, sni, res) {
 		return tls.Certificate{}, false
 	}
 
@@ -317,7 +319,7 @@ func obtainCert(acmeClient *lego.Client, domains []string, renew *certificate.Re
 			if err == nil && tlsCertificate.Leaf.NotAfter.After(time.Now()) {
 				// avoid sending a mock cert instead of a still valid cert, instead abuse CSR field to store time to try again at
 				renew.CSR = []byte(strconv.FormatInt(time.Now().Add(6*time.Hour).Unix(), 10))
-				PogrebPut(KeyDatabase, []byte(name), renew)
+				database.PogrebPut(KeyDatabase, []byte(name), renew)
 				return tlsCertificate, nil
 			}
 		}
@@ -325,7 +327,7 @@ func obtainCert(acmeClient *lego.Client, domains []string, renew *certificate.Re
 	}
 	log.Printf("Obtained certificate for %v", domains)
 
-	PogrebPut(KeyDatabase, []byte(name), res)
+	database.PogrebPut(KeyDatabase, []byte(name), res)
 	tlsCertificate, err := tls.X509KeyPair(res.Certificate, res.PrivateKey)
 	if err != nil {
 		return tls.Certificate{}, err
@@ -390,7 +392,7 @@ func mockCert(domain, msg, mainDomainSuffix string) tls.Certificate {
 	if domain == "*"+mainDomainSuffix || domain == mainDomainSuffix[1:] {
 		databaseName = mainDomainSuffix
 	}
-	PogrebPut(KeyDatabase, []byte(databaseName), res)
+	database.PogrebPut(KeyDatabase, []byte(databaseName), res)
 
 	tlsCertificate, err := tls.X509KeyPair(res.Certificate, res.PrivateKey)
 	if err != nil {
@@ -578,7 +580,7 @@ func SetupCertificates(mainDomainSuffix []byte, acmeAPI, acmeMail, acmeEabHmac,
 
 			// update main cert
 			res := &certificate.Resource{}
-			if !PogrebGet(KeyDatabase, mainDomainSuffix, res) {
+			if !database.PogrebGet(KeyDatabase, mainDomainSuffix, res) {
 				log.Printf("[ERROR] Couldn't renew certificate for main domain: %s", "expected main domain cert to exist, but it's missing - seems like the database is corrupted")
 			} else {
 				tlsCertificates, err := certcrypto.ParsePEMBundle(res.Certificate)
diff --git a/server/database/helpers.go b/server/database/helpers.go
new file mode 100644
index 0000000..b2eb017
--- /dev/null
+++ b/server/database/helpers.go
@@ -0,0 +1,38 @@
+package database
+
+import (
+	"bytes"
+	"encoding/gob"
+	"github.com/akrylysov/pogreb"
+)
+
+func PogrebPut(db *pogreb.DB, name []byte, obj interface{}) {
+	var resGob bytes.Buffer
+	resEnc := gob.NewEncoder(&resGob)
+	err := resEnc.Encode(obj)
+	if err != nil {
+		panic(err)
+	}
+	err = db.Put(name, resGob.Bytes())
+	if err != nil {
+		panic(err)
+	}
+}
+
+func PogrebGet(db *pogreb.DB, name []byte, obj interface{}) bool {
+	resBytes, err := db.Get(name)
+	if err != nil {
+		panic(err)
+	}
+	if resBytes == nil {
+		return false
+	}
+
+	resGob := bytes.NewBuffer(resBytes)
+	resDec := gob.NewDecoder(resGob)
+	err = resDec.Decode(obj)
+	if err != nil {
+		panic(err)
+	}
+	return true
+}
diff --git a/server/handler.go b/server/handler.go
index ca2872f..80c1c79 100644
--- a/server/handler.go
+++ b/server/handler.go
@@ -16,6 +16,7 @@ import (
 	"github.com/valyala/fastjson"
 
 	"codeberg.org/codeberg/pages/html"
+	"codeberg.org/codeberg/pages/server/utils"
 )
 
 // Handler handles a single HTTP request to the web server.
@@ -31,7 +32,7 @@ func Handler(mainDomainSuffix, rawDomain []byte, giteaRoot, rawInfoPage, giteaAp
 		// Enable browser caching for up to 10 minutes
 		ctx.Response.Header.Set("Cache-Control", "public, max-age=600")
 
-		trimmedHost := TrimHostPort(ctx.Request.Host())
+		trimmedHost := utils.TrimHostPort(ctx.Request.Host())
 
 		// Add HSTS for RawDomain and MainDomainSuffix
 		if hsts := GetHSTSHeader(trimmedHost, mainDomainSuffix, rawDomain); hsts != "" {
diff --git a/server/helpers.go b/server/helpers.go
index ecb4bf8..6d55ddf 100644
--- a/server/helpers.go
+++ b/server/helpers.go
@@ -2,8 +2,6 @@ package server
 
 import (
 	"bytes"
-	"encoding/gob"
-	"github.com/akrylysov/pogreb"
 )
 
 // GetHSTSHeader returns a HSTS header with includeSubdomains & preload for MainDomainSuffix and RawDomain, or an empty
@@ -15,42 +13,3 @@ func GetHSTSHeader(host, mainDomainSuffix, rawDomain []byte) string {
 		return ""
 	}
 }
-
-func TrimHostPort(host []byte) []byte {
-	i := bytes.IndexByte(host, ':')
-	if i >= 0 {
-		return host[:i]
-	}
-	return host
-}
-
-func PogrebPut(db *pogreb.DB, name []byte, obj interface{}) {
-	var resGob bytes.Buffer
-	resEnc := gob.NewEncoder(&resGob)
-	err := resEnc.Encode(obj)
-	if err != nil {
-		panic(err)
-	}
-	err = db.Put(name, resGob.Bytes())
-	if err != nil {
-		panic(err)
-	}
-}
-
-func PogrebGet(db *pogreb.DB, name []byte, obj interface{}) bool {
-	resBytes, err := db.Get(name)
-	if err != nil {
-		panic(err)
-	}
-	if resBytes == nil {
-		return false
-	}
-
-	resGob := bytes.NewBuffer(resBytes)
-	resDec := gob.NewDecoder(resGob)
-	err = resDec.Decode(obj)
-	if err != nil {
-		panic(err)
-	}
-	return true
-}
diff --git a/server/utils/utils.go b/server/utils/utils.go
new file mode 100644
index 0000000..7be330f
--- /dev/null
+++ b/server/utils/utils.go
@@ -0,0 +1,11 @@
+package utils
+
+import "bytes"
+
+func TrimHostPort(host []byte) []byte {
+	i := bytes.IndexByte(host, ':')
+	if i >= 0 {
+		return host[:i]
+	}
+	return host
+}