diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..7332a96
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,10 @@
+# Using golang:latest instead of alpine because of issues with sqlite3
+FROM golang:latest
+
+WORKDIR /app
+COPY dist/fail2ban-prometheus-exporter_linux_amd64/fail2ban-prometheus-exporter /app
+COPY docker/run.sh /app
+
+RUN chmod +x /app/*
+
+ENTRYPOINT /app/run.sh
diff --git a/Makefile b/Makefile
index 006934c..3dfe3af 100644
--- a/Makefile
+++ b/Makefile
@@ -22,3 +22,9 @@ build/snapshot:
 
 build/release:
 	./tools/goreleaser_linux_amd64 --rm-dist --skip-publish
+
+build/docker:
+	docker build -t registry.gitlab.com/hectorjsmith/fail2ban-prometheus-exporter:latest .
+
+build/docker-tag:
+	docker build -t registry.gitlab.com/hectorjsmith/fail2ban-prometheus-exporter:$(shell git describe --tags) .
diff --git a/db/db.go b/db/db.go
index 90e1788..dc759eb 100644
--- a/db/db.go
+++ b/db/db.go
@@ -70,8 +70,10 @@ func (db *Fail2BanDB) RunJailNameToCountQuery(query string) (map[string]int, err
 }
 
 func (db *Fail2BanDB) mustCloseStatement(stmt *sql.Stmt) {
-	err := stmt.Close()
-	if err != nil {
-		log.Fatal(err)
+	if stmt != nil {
+		err := stmt.Close()
+		if err != nil {
+			log.Fatal(err)
+		}
 	}
 }
diff --git a/docker/run.sh b/docker/run.sh
new file mode 100644
index 0000000..667158d
--- /dev/null
+++ b/docker/run.sh
@@ -0,0 +1,9 @@
+#/bin/sh
+
+# Print version to logs for debugging purposes
+/app/fail2ban-prometheus-exporter -version
+
+# Start the exporter (use exec to support graceful shutdown)
+# Inspired by: https://akomljen.com/stopping-docker-containers-gracefully/
+exec /app/fail2ban-prometheus-exporter \
+    -db /app/fail2ban.sqlite3