diff --git a/apps/swh-web/Dockerfile b/apps/swh-web/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..ac307fb90e9f71047fafbd8c265570a32da19194
--- /dev/null
+++ b/apps/swh-web/Dockerfile
@@ -0,0 +1,36 @@
+# Deeply inspired from the Dockerfile of the swh-storage project
+FROM python:3.10-bullseye
+
+RUN apt-get -y update && \
+    apt-get -y upgrade && \
+    apt-get install -y libcmph-dev librdkafka-dev && \
+    apt clean && \
+    addgroup --gid 1000 swh && \
+    useradd --gid 1000 --uid 1000 -m -d /srv/swh swh && \
+    mkdir -p /etc/softwareheritage /var/log/softwareheritage/webapp && \
+    chown swh:swh /var/log/softwareheritage/webapp
+
+USER swh
+WORKDIR /srv/swh
+
+COPY --chown=swh:swh requirements-frozen.txt /srv/swh
+COPY --chown=swh:swh entrypoint.sh /srv/swh
+
+ENV PYTHONPATH=/srv/swh
+ENV PATH=/srv/swh/.local/bin:$PATH
+
+RUN chmod u+x /srv/swh/entrypoint.sh && \
+    /usr/local/bin/python -m pip install --upgrade pip && \
+    pip install --no-cache-dir -r requirements-frozen.txt && \
+    pip install gunicorn
+
+ENV SWH_CONFIG_FILENAME=/etc/softwareheritage/config.yml
+ENV PORT 5004
+EXPOSE $PORT
+ENV THREADS 2
+ENV WORKERS 2
+ENV TIMEOUT 3600
+ENV DJANGO_SETTINGS_MODULE swh.web.settings.production
+ENV SWH_MAIN_PACKAGE swh.web
+
+ENTRYPOINT ["/srv/swh/entrypoint.sh"]
diff --git a/apps/swh-web/entrypoint.sh b/apps/swh-web/entrypoint.sh
new file mode 100755
index 0000000000000000000000000000000000000000..5005f7dba25647faa6b7ce3634a8aaca235e3953
--- /dev/null
+++ b/apps/swh-web/entrypoint.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+set -e
+
+case "$1" in
+    "shell")
+        exec bash -i
+        ;;
+    "cron")
+        wait-for-it swh-web:5004 -s --timeout=0
+
+        echo "Start periodic save code now refresh statuses routine (in background)"
+        exec sh -c 'trap exit TERM INT; while :; do
+        (date && django-admin refresh_savecodenow_statuses \
+                  --settings=${DJANGO_SETTINGS_MODULE} 2>&1)
+        sleep 15 &
+        wait ${!}
+        done'
+        ;;
+
+     *)
+        echo "starting the swh-web server"
+        # run gunicorn workers as in production otherwise
+        exec gunicorn \
+            --bind 0.0.0.0:${PORT} \
+            --threads ${THREADS} \
+            --workers ${WORKERS} \
+            --timeout ${TIMEOUT} \
+            --access-logfile '-' \
+            --env DJANGO_SETTINGS_MODULE=${DJANGO_SETTINGS_MODULE} \
+            --config 'python:swh.web.gunicorn_config' \
+            'django.core.wsgi:get_wsgi_application()'
+esac
diff --git a/apps/swh-web/requirements.txt b/apps/swh-web/requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..373fe55430c41a532108fd25b7b03a32d045d32e
--- /dev/null
+++ b/apps/swh-web/requirements.txt
@@ -0,0 +1 @@
+swh.web