diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index aee9248f43e3626762bd7103ca4848f506dfa5c9..6ea181f6ccdc3f220f0383c5dc26ade746eb83a4 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -179,3 +179,19 @@ push-youtube-dl:
   needs:
     - job: build-youtube-dl
       artifacts: true
+
+# postgres image:
+
+build-postgres:
+  extends: .container-build
+  variables:
+    CONTEXT: postgres
+
+push-postgres:
+  extends: .container-push
+  variables:
+    CONTEXT: postgres
+    IMAGE: postgres
+  needs:
+    - job: build-postgres
+      artifacts: true
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index ebe02f78626d6d33de69001bcd48383284ad3c20..f7cd63f337ece43d098cb05a3371f36628e84e9a 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -66,6 +66,7 @@ repos:
     rev: v0.2.0
     hooks:
       - id: shell-validate
+        exclude: postgres/healthcheck
 
   - repo: https://github.com/AleksaC/hadolint-py.git
     rev: v2.8.0
diff --git a/postgres/Dockerfile b/postgres/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..766559fce2fe0ece15249669260373ef2ba138ee
--- /dev/null
+++ b/postgres/Dockerfile
@@ -0,0 +1,3 @@
+FROM docker.io/postgres:14-alpine
+COPY --chown=root:root healthcheck /usr/local/bin/
+HEALTHCHECK --start-period=3m CMD healthcheck
diff --git a/postgres/README.md b/postgres/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..42e8063ed98a321e612e71cba4c2e6522c65c563
--- /dev/null
+++ b/postgres/README.md
@@ -0,0 +1,3 @@
+# postgres
+
+Just the upstream image but with a healthcheck.
diff --git a/postgres/healthcheck b/postgres/healthcheck
new file mode 100755
index 0000000000000000000000000000000000000000..19c1ed766eb687c28130406c38274d3ab3b6e170
--- /dev/null
+++ b/postgres/healthcheck
@@ -0,0 +1,21 @@
+#!/usr/bin/env bash
+set -eo pipefail
+
+host="$(hostname -i || echo '127.0.0.1')"
+user="${POSTGRES_USER:-postgres}"
+db="${POSTGRES_DB:-$POSTGRES_USER}"
+export PGPASSWORD="${POSTGRES_PASSWORD:-}"
+
+args=(
+	# force postgres to not use the local unix socket (test "external" connectibility)
+	--host "$host"
+	--username "$user"
+	--dbname "$db"
+	--quiet --no-align --tuples-only
+)
+
+if select="$(echo 'SELECT 1' | psql "${args[@]}")" && [ "$select" = '1' ]; then
+	exit 0
+fi
+
+exit 1