diff --git a/apps/ipfs-gateway/Dockerfile b/apps/ipfs-gateway/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..93bbac9d3a07560572d4c49a43d280a6cb2a4f9e
--- /dev/null
+++ b/apps/ipfs-gateway/Dockerfile
@@ -0,0 +1,52 @@
+#######
+# build
+#######
+# TODO: use an swh repository if it becomes a permanent thing
+ARG REPOSITORY=https://github.com/obsidiansystems/go-ipfs-swh-plugin.git
+ARG GIT_HEAD=2380683e3309e2c5bb167dbbbcb50f71eed063bb # master at 2023-01-31
+
+FROM debian:bullseye as build
+
+RUN apt update -y && apt dist-upgrade -y && apt install -y git nix
+
+RUN mkdir /src && cd /src && \
+    git clone --depth 1 https://github.com/obsidiansystems/go-ipfs-swh-plugin.git && \
+    cd go-ipfs-swh-plugin && \
+    git checkout $HEAD
+
+RUN cd /src/go-ipfs-swh-plugin && \
+    nix-build && \
+    nix-store --export $(nix-store --query --requisites ./result) > ipfs.dump
+
+# #############
+# # final image
+# #############
+
+FROM debian:bullseye
+
+RUN apt update && apt dist-upgrade -y && apt install -y nix && apt clean
+
+COPY --from=build  /src/go-ipfs-swh-plugin/ipfs.dump /tmp
+
+# Install ipfs cli with the minimalist runtime dependencies set
+RUN nix-store --import < /tmp/ipfs.dump && \
+    update-alternatives  --install /usr/bin/ipfs  ipfs /nix/store/*ipfs*/bin/ipfs 1
+
+RUN addgroup --gid 1000 ipfs && \
+    useradd --gid 1000 --uid 1000 -m ipfs
+
+USER ipfs
+WORKDIR /home/ipfs
+
+USER ipfs
+WORKDIR /data/ipfs
+ENV IPFS_PATH /data/ipfs
+
+# | true to ignore the empty directory error:
+# https://github.com/ipfs/kubo/issues/9155
+RUN ipfs init -e -p swhbridge || true && \
+  ipfs config Addresses.API /ip4/0.0.0.0/tcp/5001 && \
+  ipfs config Addresses.Gateway /ip4/0.0.0.0/tcp/8080
+
+ENTRYPOINT [ "ipfs" ]
+CMD ["daemon"]
diff --git a/apps/ipfs-gateway/Readme.md b/apps/ipfs-gateway/Readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..eb65ee78dc0ad09cb8682fa60b1c7ac77e7a70e6
--- /dev/null
+++ b/apps/ipfs-gateway/Readme.md
@@ -0,0 +1,78 @@
+# IPFS swh gateway
+
+## Usage
+
+To be able to retrieve the swh contents, the gateway uses a private SWH api endpoint.
+To do so, an SWH api token must be configured in the gateway configuration.
+
+- Bootstrap the gateway
+```
+    mkdir /srv/ipfs  # This is where the ipfs data will be stored
+    docker run --rm -ti -v /tmp/test:/data/ipfs --user $UID \
+        container-registry.softwareheritage.org/swh/infra/swh-apps/ipfs-gateway \
+        initipfs init -e -p swhbridge
+```
+WARN: ignore the ipld error (https://github.com/ipfs/kubo/issues/9155)
+
+- Edit the config file `/srv/ipfs/config` and search the Datastore.Spec.mounts section.
+- In the swhbridge child, add an `auth-token` entry:
+```json
+{
+    Datastore {
+        Spec {
+            "mounts": [
+                {
+                "child": {
+                    "type": "swhbridge",
+                    "auth-token: "<replace by the very long token>"
+                },
+            ]
+        }
+    }
+}
+```
+
+- Start the gateway with:
+```
+    docker run -d --name ipfs-gateway -p 5001:5001 -p 4001:4001/udp \
+        -v /srv/ipfs:/data/ipfs \
+        container-registry.softwareheritage.org/swh/infra/swh-apps/ipfs-gateway
+```
+
+The gateway detects the available interfaces and tries to guess its public ip address.
+```
+Swarm listening on /ip4/127.0.0.1/tcp/4001
+Swarm listening on /ip4/127.0.0.1/udp/4001/quic
+Swarm listening on /ip4/172.17.0.2/tcp/4001
+Swarm listening on /ip4/172.17.0.2/udp/4001/quic
+Swarm listening on /p2p-circuit
+Swarm announcing /ip4/127.0.0.1/tcp/4001
+Swarm announcing /ip4/127.0.0.1/udp/4001/quic
+Swarm announcing /ip4/172.17.0.2/tcp/4001
+Swarm announcing /ip4/172.17.0.2/udp/4001/quic
+Swarm announcing /ip4/1.2.3.4/udp/4001/quic   <------ the detected public address
+API server listening on /ip4/0.0.0.0/tcp/5001
+WebUI: http://0.0.0.0:5001/webui
+Gateway (readonly) server listening on /ip4/0.0.0.0/tcp/8080
+```
+
+If the annouces are not correct, it can be fixed in the configuration, the section `Adresses.Announce` and `Addresses.AppendAnnounce`
+
+**To be reachable from the internet, the port 4001 must be routed to the container**
+
+## Testing
+
+Once the gateway is up and publicly reachable, it can be tested like this:
+```
+docker run -ti --name ipfs-client --rm ipfs/kubo
+```
+On another terminal:
+
+```
+docker exec client ipfs dag get \
+    --output-codec=git-raw \
+       f0178111494a9ed024d3859793618152ea559a168bbcbb5e2
+```
+
+For more details on the ipfs usage, check at the ipfs gateway main repository:
+https://github.com/obsidiansystems/go-ipfs-swh-plugin.git