diff --git a/Dockerfile b/Dockerfile
index 8c13133546fed009ae7def54bbf03cb935d05466..59949b1ea7f074a4445c2d9c90663b62775af3c7 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,14 +1,11 @@
-FROM golang:1.20 AS gobuild
-COPY modsec_logger.go /src/modsec_logger.go
-WORKDIR /src
-RUN go build -tags netgo -o modsec_logger modsec_logger.go
-
 FROM composer:2.5.5 as build
 
 ADD . /build
 WORKDIR /build
 RUN /build/install.sh
 
+FROM registry.git.autistici.org/ai3/tools/modsec-logger:master AS modseclogger
+
 FROM registry.git.autistici.org/ai3/docker/apache2-php-base:bookworm
 
 COPY --from=build /build/app/ /opt/noblogs/www
@@ -20,7 +17,7 @@ COPY docker/wp-config.php /opt/noblogs/www/wp-config.php
 COPY docker/wp-cache-config.php /opt/noblogs/www/wp-content/wp-cache-config.php
 COPY docker/conf /tmp/conf
 COPY docker/build.sh /tmp/build.sh
-COPY --from=gobuild /src/modsec_logger /usr/local/bin/modsec_logger
+COPY --from=modseclogger /modsec-logger /usr/local/bin/modsec-logger
 
 # Install wp-cli in /usr/local/bin (aliased as "wp").
 ADD https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar /usr/local/bin/wp-cli.phar
diff --git a/docker/conf/apache2/conf-available/modsecurity-custom.conf b/docker/conf/apache2/conf-available/modsecurity-custom.conf
index 07b6877f7acaa77ee5c4660dd450e9769c1f0e44..6cad1933789f131c2e6914005b09222bb64fe268 100644
--- a/docker/conf/apache2/conf-available/modsecurity-custom.conf
+++ b/docker/conf/apache2/conf-available/modsecurity-custom.conf
@@ -6,7 +6,7 @@
                   SecRuleEngine Off
         </Location>
 
-	ErrorLog "|/usr/local/bin/modsec_logger"
+	ErrorLog "|/usr/local/bin/modsec-logger"
 
 </IfModule>
 </IfModule>
diff --git a/modsec_logger.go b/modsec_logger.go
deleted file mode 100644
index 1cab3ca83050c6e55dd6212ebfc92dc313eb9aa4..0000000000000000000000000000000000000000
--- a/modsec_logger.go
+++ /dev/null
@@ -1,76 +0,0 @@
-// Tool to rewrite mod_security2 logs (very difficult to parse
-// although they are in semi-structured format) to JSON.
-package main
-
-import (
-	"bufio"
-	"bytes"
-	"encoding/json"
-	"fmt"
-	"io"
-	"log"
-	"os"
-	"regexp"
-)
-
-var (
-	outerRx = regexp.MustCompile(`\[[^\]]+]`)
-	innerRx = regexp.MustCompile(`\[([^ ]+) \"?(.*)\"\]$`)
-	needle  = []byte("ModSecurity: ")
-)
-
-func parseModSec(w io.Writer, line []byte) bool {
-	if !bytes.Contains(line, needle) {
-		return false
-	}
-
-	fields := make(map[string]interface{})
-	var tags []string
-	for _, inner := range outerRx.FindAll(line, -1) {
-		for _, matches := range innerRx.FindAllSubmatch(inner, -1) {
-			field := string(matches[1])
-			value := string(matches[2])
-			switch field {
-			case "tag":
-				tags = append(tags, value)
-			case "client", "unique_id", "file", "line":
-				// Suppress these tags.
-			default:
-				fields[field] = value
-			}
-		}
-	}
-	if len(fields) == 0 {
-		return false
-	}
-	if len(tags) > 0 {
-		fields["tag"] = tags
-	}
-
-	data, _ := json.Marshal(fields)
-	fmt.Fprintf(w, "@cee:{\"modsec\":%s}\n", data)
-	return true
-}
-
-func writeLine(w io.Writer, line []byte) error {
-	if _, err := w.Write(line); err != nil {
-		return err
-	}
-	_, err := io.WriteString(w, "\n")
-	return err
-}
-
-func main() {
-	outw := os.Stdout
-
-	scanner := bufio.NewScanner(os.Stdin)
-	for scanner.Scan() {
-		line := scanner.Bytes()
-		if parseModSec(outw, line) {
-			continue
-		}
-		if err := writeLine(outw, line); err != nil {
-			log.Fatal(err)
-		}
-	}
-}